Re: What's the best way to minimize the need of run time checks?
On Sunday 28 August 2016 15:56, Juan Pablo Romero Méndez wrote: > 2016-08-27 21:30 GMT-07:00 Steve D'Aprano : [...] >> Now it is true that speaking in full generality, classes and types refer to >> different things. Or to be perhaps more accurate, *subclassing* and >> *subtyping* are different things: >> >> http://c2.com/cgi/wiki?SubTypingAndSubClassing >> >> Many languages treat them the same, but fundamentally they are different. > > Oh, I don't think he is thinking in terms of OO "classes", I think he meant > two different "kinds" or "varieties" of values (although kind has a > technical meaning) That's not quite right either. "Two different kinds or varieties" is what both subclassing and subtyping aim to describe, in different ways: e.g. dogs and cats are two different kinds of mammal. What you are describing here: > In TypeScript terms what he is saying can be described like this: > > type Complex = > { real: number, i: number } > | { r: number, φ: number} > > const c1: Complex = { real: 1, i: 1 } > const c2: Complex = { r: 1, φ: 0.5 } > > You have two values of the same type but different representation. seems to be more like what is called "variant record" in Pascal. http://www.freepascal.org/docs-html/ref/refsu16.html I'm not familiar with TypeScript. How does this work? If I say: const c1: Complex = {real: 1, imag: 1 } print c1.r print c1.φ what do I get? If r and φ are merely alternative names for "real" and "imag", that's not good enough. Given real=1, imag=1, then we need to get r=1.414213 and φ = pi/4 without any extra effort on the part of the user. The point is, the complex number (1, 1) in Cartesian coordinates and (sqrt(2), pi/4) in polar coordinates aren't two different kinds of things, they are two different ways of writing the same value. Like writing 1A in hex and 26 in decimal. Somebody may choose to implement this as two different classes ("CartesianComplex" and "PolarComplex") but that's a limitation of their code, or of their language, it doesn't reflect a real difference between two different kinds of things. Another way to put it: If you were programming a first person shooter game, you might choose each of the enemies as an object. Let's say you have an enemy called the Grue. You can view the Grue from the front or from the back, depending on which way it is standing when you see it. Would you implement this as two different classes? GrueSeenFromFront GrueSeenFromBack I should hope not. It's the same object, the same Grue, it just looks different depending on which way you approach it. -- Steve -- https://mail.python.org/mailman/listinfo/python-list
Re: What's the best way to minimize the need of run time checks?
Chris Angelico writes: > On Sun, Aug 28, 2016 at 4:13 PM, Jussi Piitulainen wrote: >>> This is where I'm less sure. Sometimes a variable's type should be >>> broader than just one concrete type - for instance, a variable might >>> hold 1 over here, and 1.5 over there, and thus is storing either >>> "int or float" or "any number". If you have a complex hierarchy of >>> types, how do you know that this variable should be allowed to hold >>> anything up to a certain level in the hierarchy, and no further? >> >> It's not just literal values that give potential type information in >> a dynamically typed language. Another source is functions that the >> compiler knows, and this information propagates back and forth in the >> analysis of the control flow. >> >> For example, below the compiler might infer that x must be a number >> but not a complex number, then generate one type check (which it >> might be able to prove redundant) and calls to specialized versions >> of ceiling and floor. >> >> d = ceiling(x) - floor(x) >> >> Also known is that the results of the calls are numbers and the >> difference of numbers is a number, so d gets assigned a number. >> Perhaps ceiling and floor in the language always return an int. Then >> d is known to be an int. And so on. > > Right, and I understand this concept. Consider this code: > > x = 5; > ... > if (some_condition) > x = "five"; > else > x = [0, 0, 0, 0, 0]; > > (adjust syntax to whatever language you like) > > Does this mean that the type of x is int|string|list, or will this be > an error? Assuming the condition can't be known until run time (eg it > involves user input), there's no way for a static analyzer to > differentiate between this code and the form that Steven put forward: I'm thinking of a dynamically typed language, so the type of x is the type of a value, so: Before the conditional, x is known to be 5 (an int). After the conditional, x is known to be "five" or [0,0,0,0,0] (a string or a list of int; not an int). If the next statement is to return -x, *that* is an error, because -x does not make sense after either branch of the conditional. It the next statement is to return x.swapcase(), the compiler can replace the conditional with if (some_condition) return "FIVE" # assuming local x else raise Objection("list don't have no .swapcase() method") In no case would I say that a mere assignment to a variable is a type error in a dynamically typed language. >> x = 1 >> x = "hello" # a type error, at compile time > > Simple type inference would either see this as meaning that x is > int|string, or possibly it'd say "x is an int up to that second line, > and a string thereafter" (which is basically like dynamic typing but > statically checked - it's the value, not the variable, that has a > type, and checks like x.upper() would take note of that). But if it > flags it as an error, that would basically mean that the type system > is (probably deliberately) simplistic and restrictive, requiring that > x be EITHER an integer variable OR a string variable, and not both. I'd say that the compiler of a dynamically typed language has different information about the type of (the value of) x after the first statement and after the second statement. If that is considered an error instead, as the comment says, then the language is statically typed (the type pertains to the variable). > Which is a perfectly viable stance, but I'm just not sure if it's (a) > what is done, or (b) ideal. Particularly since it'd end up requiring > some annoying rules, like "integers and floats are compatible, but > nothing else, including user-defined types" or "integers and floats > are fundamentally different things, and if you want your variable ever > to contain a float, you have to always use 1.0 instead of just 1", > neither of which I like. I suppose statically typed type-inferencing languages do that, but I don't have much experience with them. They may not be happy until they can infer a concrete implementation type for every variable, and there may be some awkward corners then. -- https://mail.python.org/mailman/listinfo/python-list
Re: What's the best way to minimize the need of run time checks?
On Sunday 28 August 2016 15:29, Chris Angelico wrote: > On Sun, Aug 28, 2016 at 2:30 PM, Steve D'Aprano > wrote: >> But the author of this piece ignores that standard distinction and invents >> his own non-standard one: to him, classes are merely different >> representations of the same data. E.g. his example of complex numbers, >> shown as Cartesian (x, y) values or polar (r, θ) values. These aren't two >> different "kinds of things", but merely two different ways of representing >> the same entity. >> >> That's not a good way to think about (say) Python lists and Python bools. >> Lists and bools are in no way the same kind of entity (except in the most >> general category of "they're both objects"). >> >> It's not even a very good way of thinking about complex numbers. > > It might be a good way of thinking about points on a Cartesian plane, > though. Rectangular and polar coordinates truly are just different > ways of expressing the same information. That's exactly my point, and that's why you shouldn't implement them as different classes. If you do, that's a limitation of your code and/or the language. (There may be *implementation specific* reasons why you are forced to, for example to avoid rounding errors due to finite precision: say, my polar number (1, 45°) may not evaluate as *exactly* (sqrt(2)/2, sqrt(2)/2) in Cartesian coordinates due to rounding. But that's a case of a leaky abstraction.) > (How well 2D coordinates map > to complex numbers is a separate question.) Mathematically speaking, they map together perfectly well. [...] > This is where I'm less sure. Sometimes a variable's type should be > broader than just one concrete type - for instance, a variable might > hold 1 over here, and 1.5 over there, and thus is storing either "int > or float" or "any number". If you have a complex hierarchy of types, > how do you know that this variable should be allowed to hold anything > up to a certain level in the hierarchy, and no further? This depends on the sophistication of the type system and support (or lack of support) for polymorphism: https://en.wikipedia.org/wiki/Polymorphism_%28computer_science%29 Type punning is normally considered a way to subvert or bypass the type system, and is normally considered a bad but necessary thing: https://en.wikipedia.org/wiki/Type_punning In general, primitive type systems like that used by Pascal (and C?) don't deal well, or at all, with the scenario you describe. Often the built-in functions can hard-code support for multiple numeric types, automatically promoting one type to another as necessary, but the same effect is almost impossible to achieve in (say) standard Pascal. Other type-checkers can deal better with polymorphism. But there's a trade-off: the more kinds of things a value or variable might be, the less certain you are of what is allowed ahead of time. That's why dynamic typed languages traditionally skipped *all* ahead-of-time type checking and instead relied entirely on runtime type errors, while traditional compilers restrict what you can do as the trade-off for catching more errors ahead of time. (That's where the reputation for flexibility of dynamic typing comes from: you never need to fight the compiler to do something you know will be okay, like passing an int to a function that expects a float.) I might be able to tell the compiler that x is Union[int, str] (a number, or a string) but that limits the ability of the compiler to tell what is and what isn't safe. If I declare that x is either an int or a str, what can we say about x.upper()? Is it safe? If x happens to be an int at the time we call x.upper(), will the language raise a runtime exception or will it blindly try to execute some arbitrary chunk of memory as the upper() method? This is why static and dynamic typing are slowly converging: statically typed languages are slowly gaining dynamic features, like C++ and vtables: https://en.wikipedia.org/wiki/Virtual_method_table while dynamically typed languages are slowly gaining smarter compilers capable of doing some "best effort" compile-time type-checking. Or at least allowing external type-checkers/linters to do so. The bottom line is that if a human reader can read the source code and deduce that x.upper() is safe because in this branch of the code, x must be a string rather than an int, then *in principle* a type-checker could do the same. Possibly better than a human, or possibly worse. Depends on the intelligence of the type-checker and the code being checked. A good enough type-checker can find infinite loops: http://perl.plover.com/yak/typing/notes.html > If what the compiler's doing is identifying what *is* assigned, then > it's easy. You've given it an int over here and a float over there, > and that's legal; from that point on, the compiler knows that this > contains either an int or a float. (Let's assume it can't know for > sure which, eg it has "if (cond) x=
Multimeter USB output
Am 28.08.2016 um 00:45 schrieb Terry Reedy: > On 8/27/2016 3:35 PM, Joe wrote: >> Hi, >> >> I'm using Python 3.5.1 with PyUSB 1.0 under Win 10 (64). We try to read >> the USB output of a DMM 'UT61B'. >> >> import usb.core >> import usb.util >> import usb.backend.libusb1 >> >> def Gosub(): >> dev = usb.core.find(idVendor=0x1a86, idProduct=0xe008) # Digital >> Multimeter UT61B >> if dev == None: >> print ('Multimeter not found') >> else: >> print ('Multimeter was found') >> dev.set_configuration() >> cfg = dev.get_active_configuration() >> intf = cfg[(0,0)] >> ep = usb.util.find_descriptor( >> intf, >> custom_match = \ >> lambda e: \ >> usb.util.endpoint_direction(e.bEndpointAddress) == \ >> usb.util.ENDPOINT_IN) >> if ep == None: >> print ('ep is None') >> else: >> s = ep.read(64, 500) >> print ('Len s: ' + len(s)) >> >> print ('Starting') >> Gosub() >> print ('Ready.-') >> >> Result: > > I presume you saw > Starting > Multimeter was found > >> File "d:\work-d\PythonProgs\ut61b.py", line 27, in >>Gosub() >> File "d:\work-d\PythonProgs\ut61b.py", line 23, in Gosub >>s = ep.read(64, 500) >> File "D:\Python3\Lib\site-packages\usb\core.py", line 402, in read >>return self.device.read(self, size_or_buffer, timeout) >> File "D:\Python3\Lib\site-packages\usb\core.py", line 988, in read >>self.__get_timeout(timeout)) >> File "D:\Python3\Lib\site-packages\usb\backend\libusb1.py", line 851, in >> intr_read >>timeout) >> File "D:\Python3\Lib\site-packages\usb\backend\libusb1.py", line 936, in >> __read >>_check(retval) >> File "D:\Python3\Lib\site-packages\usb\backend\libusb1.py", line 595, in >> _check >>raise USBError(_strerror(ret), ret, _libusb_errno[ret]) >> >> usb.core.USBError: [Errno 10060] Operation timed out >> >> What's wrong? How to fix? > > Read (again?) the doc for the interface for the device. Because reading > timed out, I suspect that it is waiting for a command for it to send > something. > Yes, I saw this: Starting Multimeter was found The UT61B has two interfaces, a RS232C interface and this usb interface. The RS232 interface works well with PySerial. It continously transmits 2 .. 3 Pakets per second with 14 Bytes each. This happens unsolicited without any command as long as the RS232C/USB button on the DMM is active. So I assumed the USB interface also doesn't need any command and also transmit this stream of 2 to 3 Pakets per second. But unfortunately I don't have any doc for the USB interface for this device. To the accompanying software of the UT61B there is a ready windos app which shows and logs the output of the UT61B. This app can be switched between RS232C and USB; both work. I asked the manufacturer (Uni-T in Shenzen) for additional info and are now waiting for an answer. Assumed the USB interface sends this 2 to 3 pakets per second unsolicited - should the code shown work? Is this ok: >> lambda e: \ >> usb.util.endpoint_direction(e.bEndpointAddress) == \ >> usb.util.ENDPOINT_IN) I am in doubt: Is usb.util.ENDPOINT_IN really correct? Thanx - Joe -- https://mail.python.org/mailman/listinfo/python-list
Re: What's the best way to minimize the need of run time checks?
On Sun, Aug 28, 2016 at 6:33 PM, Steven D'Aprano wrote: > On Sunday 28 August 2016 15:29, Chris Angelico wrote: >> It might be a good way of thinking about points on a Cartesian plane, >> though. Rectangular and polar coordinates truly are just different >> ways of expressing the same information. > > That's exactly my point, and that's why you shouldn't implement them as > different classes. If you do, that's a limitation of your code and/or the > language. > > (There may be *implementation specific* reasons why you are forced to, for > example to avoid rounding errors due to finite precision: say, my polar number > (1, 45°) may not evaluate as *exactly* (sqrt(2)/2, sqrt(2)/2) in Cartesian > coordinates due to rounding. But that's a case of a leaky abstraction.) class Complex(complex): @property def r(self): return abs(self) @property def phi(self): return cmath.phase(self) One value, two ways of looking at it. One type. One class. > I might be able to tell the compiler that x is Union[int, str] (a number, or a > string) but that limits the ability of the compiler to tell what is and what > isn't safe. If I declare that x is either an int or a str, what can we say > about x.upper()? Is it safe? If x happens to be an int at the time we call > x.upper(), will the language raise a runtime exception or will it blindly try > to execute some arbitrary chunk of memory as the upper() method? That's fine if you *tell* the compiler this. My question came from your statement that a type *inference* system can detect errors of assignment - not method/operator usage. A dynamic type inference system could easily cope with this: x = 5 y = x**2 x = "five" z = x.upper() and correctly deduce that, at the time of y's assignment, exponentiation of x was legal, and at the time of z's, uppercasing was. But you said that the type system could flag the third line as an error, saying "hey, I'm expecting this to be integers only". Here's what you said: > x = 1 > x = "hello" # a type error, at compile time If I were doing type inference, with my limited knowledge of the field, I would do one of two things: 1) Infer that x holds only integers (or maybe broaden it to "numbers"), and then raise an error on the second line; this basically restricts the type system to be union-free 2) Infer that x holds Union[int, str] in PEP 484 notation, or int|string in Pike notation, and permit it to carry either type. Which way is it? Do you get errors, as per your example, and thus are never allowed to have union types? And if so, what happens with compatible types (notably, int and float)? Can user-defined types be deemed "compatible"? Are the same types always compatible? Or are no types ever compatible, and you just have a single Number type, like in ECMAScript? > Okay. What happens when you say: > > if random() < 0.5: > x = 1234 > else: > x = "surprise!" > > y = 3*(x + 1) > z = x.find("p") # or however Pike does string functions/methods > > > What is y? What is z? In Pike, variables get declared. So we have a few possibilities: 1) Declaration was "int x;" and the else clause is a compile-time error 2) Declaration was "string x;" and the converse 3) Declaration was "int|string x;" or "mixed x;" or some other broad form, and they are both accepted. > There are solutions to this conundrum. One is weak typing: 3*("surprise!" + 1) > evaluates as 3*(0 + 1) or just 3, while (1234).find("p") coerces 1234 to the > string "1234". > > Another is runtime exceptions. In this example, y would be "surprise!1surprise!1surprise!1", because Pike allows strings and integers to be added (representing the int with ASCII decimal digits), but if the expression were 3*(x-1) instead, then these would be run-time exceptions. Pike, like Python, strongly types its values, so if the variable declaration doesn't prevent something illogical from being compiled, it'll throw a nice tidy exception at you. The find method, being applied to an integer, would definitely be an exception, more-or-less "integers don't have such a method, moron". > A third is "don't do that, if you do, you can deal with the segmentation > fault". Only in C, where segfaults are considered a normal part of life. In high level languages, no thank you. > A fourth would be that the type-checker is smart enough to recognise that only > one of those two assignments is valid, the second must be illegal, and flag > the > whole thing. That's what a human would do -- I don't know if any type systems > are that sophisticated. Ooh that would be VERY sophisticated. I don't know of anything that does that, but it could be done on the same basis as the C "undefined behaviour" thing you so revile against - basically, the compiler says "well, if the programmer knows what he's doing, x MUST be an integer at this point, ergo I can assume that it really will be an integer". I've seen levels of sophistication like that in tools like Coverity and how it detects
Re: Is duck-typing misnamed?
Am 28.08.2016 um 00:34 schrieb Terry Reedy: On 8/26/2016 7:58 PM, ROGER GRAYDON CHRISTMAN wrote: "If it walks like a duck, quacks like a duck,... " so there is indeed precedence for this so-called 'duck typing' but wouldn't it be more Pythonic to call this 'witch typing'? "How do you know she is a witch?" "She looks like one." Given that people were once burned to death for 'looking like a witch' (or sounding or acting), and can still suffer socially for such reasons, this it not funny to me. We should stick with ducks. Agree. -- https://mail.python.org/mailman/listinfo/python-list
Re: Multimeter USB output
On 8/28/2016 5:13 AM, Joe wrote: Am 28.08.2016 um 00:45 schrieb Terry Reedy: On 8/27/2016 3:35 PM, Joe wrote: Hi, I'm using Python 3.5.1 with PyUSB 1.0 under Win 10 (64). We try to read the USB output of a DMM 'UT61B'. import usb.core import usb.util import usb.backend.libusb1 def Gosub(): dev = usb.core.find(idVendor=0x1a86, idProduct=0xe008) # Digital Multimeter UT61B if dev == None: print ('Multimeter not found') else: print ('Multimeter was found') dev.set_configuration() cfg = dev.get_active_configuration() intf = cfg[(0,0)] ep = usb.util.find_descriptor( intf, custom_match = \ lambda e: \ usb.util.endpoint_direction(e.bEndpointAddress) == \ usb.util.ENDPOINT_IN) if ep == None: print ('ep is None') else: s = ep.read(64, 500) print ('Len s: ' + len(s)) print ('Starting') Gosub() print ('Ready.-') Result: I presume you saw Starting Multimeter was found File "d:\work-d\PythonProgs\ut61b.py", line 27, in Gosub() File "d:\work-d\PythonProgs\ut61b.py", line 23, in Gosub s = ep.read(64, 500) File "D:\Python3\Lib\site-packages\usb\core.py", line 402, in read return self.device.read(self, size_or_buffer, timeout) File "D:\Python3\Lib\site-packages\usb\core.py", line 988, in read self.__get_timeout(timeout)) File "D:\Python3\Lib\site-packages\usb\backend\libusb1.py", line 851, in intr_read timeout) File "D:\Python3\Lib\site-packages\usb\backend\libusb1.py", line 936, in __read _check(retval) File "D:\Python3\Lib\site-packages\usb\backend\libusb1.py", line 595, in _check raise USBError(_strerror(ret), ret, _libusb_errno[ret]) usb.core.USBError: [Errno 10060] Operation timed out What's wrong? How to fix? Read (again?) the doc for the interface for the device. Because reading timed out, I suspect that it is waiting for a command for it to send something. Yes, I saw this: Starting Multimeter was found The UT61B has two interfaces, a RS232C interface and this usb interface. The RS232 interface works well with PySerial. It continously transmits 2 .. 3 Pakets per second with 14 Bytes each. This happens unsolicited without any command as long as the RS232C/USB button on the DMM is active. So I assumed the USB interface also doesn't need any command and also transmit this stream of 2 to 3 Pakets per second. But unfortunately I don't have any doc for the USB interface for this device. To the accompanying software of the UT61B there is a ready windos app which shows and logs the output of the UT61B. This app can be switched between RS232C and USB; both work. I asked the manufacturer (Uni-T in Shenzen) for additional info and are now waiting for an answer. Assumed the USB interface sends this 2 to 3 pakets per second unsolicited - should the code shown work? Is this ok: lambda e: \ usb.util.endpoint_direction(e.bEndpointAddress) == \ usb.util.ENDPOINT_IN) I am in doubt: Is usb.util.ENDPOINT_IN really correct? I do not know as I have not used the usb package. -- Terry Jan Reedy -- https://mail.python.org/mailman/listinfo/python-list
Re: What's the best way to minimize the need of run time checks?
2016-08-28 0:04 GMT-07:00 Steven D'Aprano < steve+comp.lang.pyt...@pearwood.info>: > On Sunday 28 August 2016 15:56, Juan Pablo Romero Méndez wrote: > > > 2016-08-27 21:30 GMT-07:00 Steve D'Aprano : > [...] > >> Now it is true that speaking in full generality, classes and types > refer to > >> different things. Or to be perhaps more accurate, *subclassing* and > >> *subtyping* are different things: > >> > >> http://c2.com/cgi/wiki?SubTypingAndSubClassing > >> > >> Many languages treat them the same, but fundamentally they are > different. > > > > Oh, I don't think he is thinking in terms of OO "classes", I think he > meant > > two different "kinds" or "varieties" of values (although kind has a > > technical meaning) > > That's not quite right either. "Two different kinds or varieties" is what > both > subclassing and subtyping aim to describe, in different ways: e.g. dogs and > cats are two different kinds of mammal. > > What you are describing here: > > > In TypeScript terms what he is saying can be described like this: > > > > type Complex = > > { real: number, i: number } > > | { r: number, φ: number} > > > > const c1: Complex = { real: 1, i: 1 } > > const c2: Complex = { r: 1, φ: 0.5 } > > > > You have two values of the same type but different representation. > > seems to be more like what is called "variant record" in Pascal. > > http://www.freepascal.org/docs-html/ref/refsu16.html > > > I'm not familiar with TypeScript. How does this work? If I say: > > const c1: Complex = {real: 1, imag: 1 } > > print c1.r > print c1.φ > > what do I get? If r and φ are merely alternative names for "real" and > "imag", > that's not good enough. Given real=1, imag=1, then we need to get > r=1.414213 > and φ = pi/4 without any extra effort on the part of the user. > > Here's a more complete example: type CartesianC = { real: number, i: number } type PolarC = { r: number, φ: number} type Complex = PolarC | CartesianC const c1: Complex = { real: 1, i: 1 }; const c2: Complex = { r: 1, φ: 0.5 }; // This is called a Type Guard function isCartesian(c: Complex): c is CartesianC { return ( c).real !== undefined; } if(isCartesian(c1)) { // c1 is a CartesianC here c1.real } else { // and a PolarC here. Using c1.real is a compile error c1.r } TypeScript doesn't support pattern matching so there's some boilerplate involved: you need to define a TypeGuard so that inside the if branch TS allows you to treat c1 as a CartesianC; within the else branch it is treated as a PolarC. > > The point is, the complex number (1, 1) in Cartesian coordinates and > (sqrt(2), > pi/4) in polar coordinates aren't two different kinds of things, they are > two > different ways of writing the same value. Like writing 1A in hex and 26 in > decimal. Somebody may choose to implement this as two different classes > ("CartesianComplex" and "PolarComplex") but that's a limitation of their > code, > or of their language, it doesn't reflect a real difference between two > different kinds of things. > Well conceptually you might think of c1 as the abstract representation of a complex number but at runtime they have very different constitutions. > > Another way to put it: > > If you were programming a first person shooter game, you might choose each > of > the enemies as an object. Let's say you have an enemy called the Grue. You > can > view the Grue from the front or from the back, depending on which way it is > standing when you see it. Would you implement this as two different > classes? > > GrueSeenFromFront > > GrueSeenFromBack > > I should hope not. It's the same object, the same Grue, it just looks > different > depending on which way you approach it. > > > > > > -- > Steve > > -- > https://mail.python.org/mailman/listinfo/python-list > -- https://mail.python.org/mailman/listinfo/python-list
Re: Is duck-typing misnamed?
On 8/27/2016 7:28 PM, ROGER GRAYDON CHRISTMAN wrote: > Your response is appreciated. I just thought I'd comment a little more on > the > script: > > Woman: I'm not a witch! I'm not a witch! > > V: ehh... but you are dressed like one. > > W: They dressed me up like this! > > All: naah no we didn't... no. > > W: And this isn't my nose, it's a false one. > > (V lifts up carrot) > > V: Well? > > P1: Well we did do the nose > > V: The nose? > > P1: ...And the hat, but she is a witch! > > > They took a woman who originally, I think we might agree, was not a witch, > and they added features that were understood to be part of the protocol > for witchiness. not a witch?? https://www.youtube.com/watch?v=zrzMhU_4m-g start at 3:30 listen to what she says after they discover she weights as much as a duck. -- https://mail.python.org/mailman/listinfo/python-list
Re: Is duck-typing misnamed?
On 08/27/2016 05:28 PM, ROGER GRAYDON CHRISTMAN wrote: > They took a woman who originally, I think we might agree, was not a witch, Umm no, she was actually a witch. Which makes the scene even funnier. "Fair caught," she says at the end. -- https://mail.python.org/mailman/listinfo/python-list
Re: What's the best way to minimize the need of run time checks?
On Sun, 28 Aug 2016 07:28 pm, Chris Angelico wrote: > On Sun, Aug 28, 2016 at 6:33 PM, Steven D'Aprano > wrote: >> On Sunday 28 August 2016 15:29, Chris Angelico wrote: >>> It might be a good way of thinking about points on a Cartesian plane, >>> though. Rectangular and polar coordinates truly are just different >>> ways of expressing the same information. >> >> That's exactly my point, and that's why you shouldn't implement them as >> different classes. If you do, that's a limitation of your code and/or the >> language. [... snip digression over possible leaky abstractions due to floating point rounding ...] > class Complex(complex): > @property > def r(self): > return abs(self) > @property > def phi(self): > return cmath.phase(self) > > One value, two ways of looking at it. One type. One class. I can't tell if you're saying this to agree with me or to disagree with me. >> I might be able to tell the compiler that x is Union[int, str] (a number, >> or a string) but that limits the ability of the compiler to tell what is >> and what isn't safe. If I declare that x is either an int or a str, what >> can we say about x.upper()? Is it safe? If x happens to be an int at the >> time we call x.upper(), will the language raise a runtime exception or >> will it blindly try to execute some arbitrary chunk of memory as the >> upper() method? > > That's fine if you *tell* the compiler this. I trust you don't actually mean that it is fine for a high-level (non-assembly) language to blindly execute some arbitrary memory address. > My question came from > your statement that a type *inference* system can detect errors of > assignment - not method/operator usage. Ignore the question of inference versus declaration. At least for simple cases, there's no real difference between the C-like declaration and assignment: int x = 5; and the assignment: x = 5; It doesn't require super-human, or even human, intelligence to infer that if x is assigned the value 5, x must be an int. So a *simple* inference engine isn't very sophisticated. Your question seems to be, what happens if you follow that with an assignment to a different type? x = 5 some_code(x) x = "hello world" Will the type-checker consider that an error ("you're assigning a str to an int") or will it infer that x is the Union[int, str]? Surely that depends on the type-checker! I don't think there's any hard and fast rule about that, but as far as I know, all statically typed languages consider than an error. Remember, that's the definition of *static typing*: the variable carries the type, not the value. So x is an int, and "hello world" isn't an int, so this MUST be an error. In dynamically typed languages... I don't know. I think that (again) I would expect that *by default* the checker should treat this as an invalid assignment. The whole point of a static type-checker is to bring some simulacrum of static typing to a dynamic language, so if you're going to enthusiastically infer union types every time you see an unexpected type assignment, it sort of defeats the purpose... "x was declared int, and you then call function foo() which is declared to return an int, but sometimes returns a str... oh, they must have meant a union, so that's okay..." > A dynamic type inference > system could easily cope with this: > > x = 5 > y = x**2 > x = "five" > z = x.upper() > > and correctly deduce that, at the time of y's assignment, > exponentiation of x was legal, and at the time of z's, uppercasing > was. Could it? Do you have an example of a language or type-checker that can do that? This isn't a rhetorical question. My understanding is that all the standard algorithms for checking types are based on the principle that a variable only has a single type in any one scope. Global x and local x may be different, but once you explicitly or implicitly set x to an int, then you can't set it to a str. So I'm not sure that existing compile-time type-checkers could deal with that, even in a dynamic language. At best they might say "oh well, x is obviously duck-typed, so don't bother trying to check it". At least that's my understanding -- perhaps I'm wrong. I daresay that what you want is *possible*. If the human reader can do it, then an automated checker should be able to. The question is not "is this possible?" but "has anyone done it yet?". > But you said that the type system could flag the third line as an > error, saying "hey, I'm expecting this to be integers only". Here's > what you said: > >> x = 1 >> x = "hello" # a type error, at compile time > > If I were doing type inference, with my limited knowledge of the > field, I would do one of two things: > > 1) Infer that x holds only integers (or maybe broaden it to > "numbers"), and then raise an error on the second line; this basically > restricts the type system to be union-free No, it only means that the system won't *infer* type unions just from assignmen
Re: Is duck-typing misnamed?
On Sun, 28 Aug 2016 08:34 am, Terry Reedy wrote: > On 8/26/2016 7:58 PM, ROGER GRAYDON CHRISTMAN wrote: >> "If it walks like a duck, quacks like a duck,... " >> >> so there is indeed precedence for this so-called 'duck typing' >> >> >> but wouldn't it be more Pythonic to call this 'witch typing'? >> >> "How do you know she is a witch?" >> >> "She looks like one." > > Given that people were once burned to death for 'looking like a witch' > (or sounding or acting), and can still suffer socially for such reasons, > this it not funny to me. We should stick with ducks. Black humour is still humour. And it is an important way of dealing with distress, and of instituting social change. Belief in the supernatural and superstition is on the rise again, including witchcraft. If it were limited to just a few benighted and ignorant migrants from Africa, that would be bad enough, but I see disturbing signs that the Satanic Ritual panic from the 80s and 90s is on its way back. (Or perhaps it never quite went away, just faded from the headlines.) Likewise the anti-paedophile frenzy, where the mere (false) accusation of paedophilia is enough to start a frenzy of abuse and even killing: http://www.telegraph.co.uk/news/uknews/crime/10422771/How-wild-rumour-led-a-mob-to-murder-an-innocent-man.html Black humour is a weapon against the ignorance and intolerance that feeds hate crimes and witch hunts (whether legally sanctioned or not, whether about literal witches or any other demonised subgroup). We can and should take every opportunity to remind people of the absurdity of relying on torture to gain confessions, and the abuses of this sort of single-minded, hysterical moral panic. And humour is a most effective way to do so. Nobody likes to be hectored and lectured as I'm lecturing you now *wink* but turning it into a joke can get the point across. We should not lose sight of the economic, political, racial reasons for witch-hunts, but equally we should not forget that when a moral panic is in full force, people behave absurdly, and the best antidote to absurd behaviour is to take the mickey out of it. -- Steve “Cheer up,” they said, “things could be worse.” So I cheered up, and sure enough, things got worse. -- https://mail.python.org/mailman/listinfo/python-list
Re: What's the best way to minimize the need of run time checks?
On Mon, Aug 29, 2016 at 12:43 PM, Steve D'Aprano wrote: > On Sun, 28 Aug 2016 07:28 pm, Chris Angelico wrote: > >> On Sun, Aug 28, 2016 at 6:33 PM, Steven D'Aprano >> wrote: >>> On Sunday 28 August 2016 15:29, Chris Angelico wrote: It might be a good way of thinking about points on a Cartesian plane, though. Rectangular and polar coordinates truly are just different ways of expressing the same information. >>> >>> That's exactly my point, and that's why you shouldn't implement them as >>> different classes. If you do, that's a limitation of your code and/or the >>> language. > [... snip digression over possible leaky abstractions due to floating point > rounding ...] > >> class Complex(complex): >> @property >> def r(self): >> return abs(self) >> @property >> def phi(self): >> return cmath.phase(self) >> >> One value, two ways of looking at it. One type. One class. > > I can't tell if you're saying this to agree with me or to disagree with me. Agreeing, and positing that you don't even need two ways of storing it (modulo FP rounding) - just two ways of *looking* at it. >>> I might be able to tell the compiler that x is Union[int, str] (a number, >>> or a string) but that limits the ability of the compiler to tell what is >>> and what isn't safe. >> >> That's fine if you *tell* the compiler this. > > I trust you don't actually mean that it is fine for a high-level > (non-assembly) language to blindly execute some arbitrary memory address. Quote trimmed to clarify my point. Of course I don't want a high level language to blindly execute random memory. > Your question seems to be, what happens if you follow that with an > assignment to a different type? > > x = 5 > some_code(x) > x = "hello world" > > > Will the type-checker consider that an error ("you're assigning a str to an > int") or will it infer that x is the Union[int, str]? > > Surely that depends on the type-checker! I don't think there's any hard and > fast rule about that, but as far as I know, all statically typed languages > consider than an error. Remember, that's the definition of *static typing*: > the variable carries the type, not the value. So x is an int, and "hello > world" isn't an int, so this MUST be an error. So in statically-typed inferred-type languages, unions are impossible. Got it. That's perfectly acceptable with strings and integers, but ints and floats are more problematic. More on that below. > In dynamically typed languages... I don't know. I think that (again) I would > expect that *by default* the checker should treat this as an invalid > assignment. The whole point of a static type-checker is to bring some > simulacrum of static typing to a dynamic language, so if you're going to > enthusiastically infer union types every time you see an unexpected type > assignment, it sort of defeats the purpose... > > "x was declared int, and you then call function foo() which is declared to > return an int, but sometimes returns a str... oh, they must have meant a > union, so that's okay..." Not really; you forfeit any kind of assignment checking (since assignment will simply expand the type union), but you still get static type checking of operators, methods, attributes, etc, and of function calls (passing a string|int to something that expects a list? Error!). You still get a lot of the benefit. >> A dynamic type inference >> system could easily cope with this: >> >> x = 5 >> y = x**2 >> x = "five" >> z = x.upper() >> >> and correctly deduce that, at the time of y's assignment, >> exponentiation of x was legal, and at the time of z's, uppercasing >> was. > > Could it? Do you have an example of a language or type-checker that can do > that? This isn't a rhetorical question. No, I don't, because the type-checking languages I use have declarations. But since C compilers are capable of detecting that "this variable isn't used after this point, so I can reuse its register", the equivalent in type checking should be possible. > My understanding is that all the standard algorithms for checking types are > based on the principle that a variable only has a single type in any one > scope. Global x and local x may be different, but once you explicitly or > implicitly set x to an int, then you can't set it to a str. So I'm not sure > that existing compile-time type-checkers could deal with that, even in a > dynamic language. At best they might say "oh well, x is obviously > duck-typed, so don't bother trying to check it". > > At least that's my understanding -- perhaps I'm wrong. > > I daresay that what you want is *possible*. If the human reader can do it, > then an automated checker should be able to. The question is not "is this > possible?" but "has anyone done it yet?". Understood. That's what I wanted to clear up - that type inference systems aim for a single type for any given variable. > No, it only means that the system won't *infer* type unions just from > assignment. And t