[Wild Idea] Static Ducks
I do not expect this idea to gain much traction but it has been an idea rolling around in my head for a year or two, so I decided to write it all down and see what other thought. Abstract: Python does not currently support static typing of variables, which is something I like, but there are times it would be nice to have static typing for variables, or method/function return values. Static Ducks should be able to run along side or imported to code that does not use Static Ducks. Actual runtime enforcement of Static Ducks should be off by default and require activation either via the command line or at the top of a file (similar to the __future__ requirement) where it would affect only that file (and any Static Ducks imported to it) Design Goals: The new syntax should * Be simple to read * Make it obvious what is happening; at the very least it should be obvious that new users can safely ignore it when writing their own code * Allow future compilers to optimize for Static Typing. * Work within a function or method definition to ensure a passed variable is the proper type * Allow Functions/Methods return values to be typed and checked * Raise an TypeError exception when the variable is set to something improper, or the function/method tries to return an improper value Issues: If this PEP is implemented it may conflict with PEP 362 (Function Signature Object) Use Cases: Python to C compilers could be enhanced by allowing static ducks. IDE's code complete could be enhanced by having static ducks available IDE's issues prediction could be enhanced to detect type issues for code that uses static ducks (Like any static typed language) Syntax Idea: """$type variable = value $returnType def function($type variable): #do stuff return value $returnType def function($type variable): #do stuff return value class test: $type variable = value $returnType def method(self, $type variable): #do stuff return value""" The reason I selected $type is because I couldn't think of anything else that $ was used for and I wanted a syntax similar to Decorators and similar to other statically typed languages. All types allow None or their proper type when setting, this so people can have typed variables that can be "undefined" for checking Example: $int count = 0 $bool def check($string testValue): return testValue.lower() == "true" class test: $string _name = None $string def get_name(self): return self._name def set_name(self, $string name): self._name = name Usage Details: When a variable has been statically type, any time it is set later its type needs to be verified. I see this working in a similar way to how properties work. Also using this style would allow people to create their own static ducks. """psudo-code class StaticDuckBase(object): _value = None class IntTypeClass(StaticDuckBase): def _get_value(self): return self._value def _set_value(self, val): if isinstance(val, (int, type(None))): self._value = val else: try: val = int(val) self._value = val except: raise TypeError("Expected int, got " + str(type(val)) + " instead!") value = property(_get_value, _set_value, None) class MyTypeClass(StaticDuckBase): def _get_value(self): return self._value def _set_value(self, val): if isinstance(val, MyType)): self._value = val else: raise TypeError("Expected MyType, got " + str(type(val)) + " instead!") value = property(_get_value, _set_value, None) staticducks.add('mytype', MyTypeClass) """ Though there will need to be some way to check if a variable is statically typed so that when you do $int count = 0 then later count = 5 it uses the static typing. Also if no static duck is specified it should revert to nonstatic but emit a warning that is only show when run with the -W option Type List: Base Types: $int $float $bool $string $tuple $namedtuple $list $set $frozenset $dict $byte $bytearray $memoryview $nonstatic # This means treat it as if it were not statically typed Composite type $bytes -> $byte | $bytearray $number -> $int | $float | Decimal $seq -> $tuple | $list | $set | $frozenset | $namedtuple $sets -> $set | $frozenset Special Cases #lets you require a specific type for keys and values $dict($type key[, $type value]) """eg $dict($int, $string) tmp = {} # creates a dict that requires ints as keys and strings as values $dict($nonstatic, $bool) tmp = {} # creates a dict that requires values to be bool, but keys can be anything """ $tuple($type value) # lets you specify the type for the tuples values $list($type value) # lets you specify the type for the lists values $set($type value) # lets you specify the type for the sets values $frozenset($type value) # lets you specify the type for the sets values $sets($type value) # lets you specify the type for the sets values $seq($type value) # lets you specify the type for the sequence values $string(encoding="UTF-8", normalized=False) $normalized # This would be equiv of doing $string(normalized=True) $normalized(encoding="UTF-8")
I've seen type checking decorators that do what I think you're describing - run-time type checking. Example 4 in PEP318 comes to mind: http://www.python.org/dev/peps/pep-0318/#examples Probably won't be added to the language syntax, however, although I could see it sometimes being useful. Cheers, Andrey On Sat, Sep 19, 2009 at 4:19 AM, Dj Gilcrease <digitalxero@gmail.com> wrote:
I do not expect this idea to gain much traction but it has been an idea rolling around in my head for a year or two, so I decided to write it all down and see what other thought.
Abstract: Python does not currently support static typing of variables, which is something I like, but there are times it would be nice to have static typing for variables, or method/function return values.
Static Ducks should be able to run along side or imported to code that does not use Static Ducks. Actual runtime enforcement of Static Ducks should be off by default and require activation either via the command line or at the top of a file (similar to the __future__ requirement) where it would affect only that file (and any Static Ducks imported to it)
Design Goals: The new syntax should * Be simple to read * Make it obvious what is happening; at the very least it should be obvious that new users can safely ignore it when writing their own code * Allow future compilers to optimize for Static Typing. * Work within a function or method definition to ensure a passed variable is the proper type * Allow Functions/Methods return values to be typed and checked * Raise an TypeError exception when the variable is set to something improper, or the function/method tries to return an improper value
Issues: If this PEP is implemented it may conflict with PEP 362 (Function Signature Object)
Use Cases: Python to C compilers could be enhanced by allowing static ducks. IDE's code complete could be enhanced by having static ducks available IDE's issues prediction could be enhanced to detect type issues for code that uses static ducks (Like any static typed language)
Syntax Idea: """$type variable = value
$returnType def function($type variable): #do stuff return value
$returnType def function($type variable): #do stuff return value
class test: $type variable = value
$returnType def method(self, $type variable): #do stuff return value"""
The reason I selected $type is because I couldn't think of anything else that $ was used for and I wanted a syntax similar to Decorators and similar to other statically typed languages.
All types allow None or their proper type when setting, this so people can have typed variables that can be "undefined" for checking
Example: $int count = 0
$bool def check($string testValue): return testValue.lower() == "true"
class test: $string _name = None
$string def get_name(self): return self._name
def set_name(self, $string name): self._name = name
Usage Details: When a variable has been statically type, any time it is set later its type needs to be verified. I see this working in a similar way to how properties work. Also using this style would allow people to create their own static ducks.
"""psudo-code class StaticDuckBase(object): _value = None
class IntTypeClass(StaticDuckBase): def _get_value(self): return self._value
def _set_value(self, val): if isinstance(val, (int, type(None))): self._value = val else: try: val = int(val) self._value = val except: raise TypeError("Expected int, got " + str(type(val)) + " instead!")
value = property(_get_value, _set_value, None)
class MyTypeClass(StaticDuckBase): def _get_value(self): return self._value
def _set_value(self, val): if isinstance(val, MyType)): self._value = val else: raise TypeError("Expected MyType, got " + str(type(val)) + " instead!")
value = property(_get_value, _set_value, None)
staticducks.add('mytype', MyTypeClass) """
Though there will need to be some way to check if a variable is statically typed so that when you do $int count = 0 then later count = 5 it uses the static typing. Also if no static duck is specified it should revert to nonstatic but emit a warning that is only show when run with the -W option
Type List: Base Types: $int $float $bool $string $tuple $namedtuple $list $set $frozenset $dict $byte $bytearray $memoryview $nonstatic # This means treat it as if it were not statically typed
Composite type $bytes -> $byte | $bytearray $number -> $int | $float | Decimal $seq -> $tuple | $list | $set | $frozenset | $namedtuple $sets -> $set | $frozenset
Special Cases #lets you require a specific type for keys and values $dict($type key[, $type value]) """eg $dict($int, $string) tmp = {} # creates a dict that requires ints as keys and strings as values $dict($nonstatic, $bool) tmp = {} # creates a dict that requires values to be bool, but keys can be anything """
$tuple($type value) # lets you specify the type for the tuples values $list($type value) # lets you specify the type for the lists values $set($type value) # lets you specify the type for the sets values $frozenset($type value) # lets you specify the type for the sets values $sets($type value) # lets you specify the type for the sets values $seq($type value) # lets you specify the type for the sequence values
$string(encoding="UTF-8", normalized=False) $normalized # This would be equiv of doing $string(normalized=True) $normalized(encoding="UTF-8") _______________________________________________ Python-ideas mailing list Python-ideas@python.org http://mail.python.org/mailman/listinfo/python-ideas
On Sat, 19 Sep 2009 06:19:25 pm Dj Gilcrease wrote:
I do not expect this idea to gain much traction but it has been an idea rolling around in my head for a year or two, so I decided to write it all down and see what other thought.
For starters, it's not clear what a static duck is. Is it a type? Is it a syntax? Is it an extension to existing built-in types? All of the above? When enabled, does the compiler do the type checking at compile time? Does it happen at runtime? Both? What sort of type checking is done? Pascal-style declarative type checking, or Haskell-style type inference? Why "static duck"? What does this have to do with duck typing? Rather than give an implementation of how users can create their own static ducks, it would be better to give some use-cases for where you would use them and what the behaviour is. -- Steven D'Aprano
On 19 Sep 2009, at 11:16 , Steven D'Aprano wrote:
What sort of type checking is done? Pascal-style declarative type checking, or Haskell-style type inference? Can't answer the rest, but from his examples and if $type and $returnType are indeed type specifications placeholders (which would be the ducks), it would be a java-style static type system (…).
And it would probably be run at "compile" time given the name, doing the checking at runtime wouldn't be very static. As far as I'm concerned, it's a terrible idea. Because it doesn't fit well within Python as a dynamically typed language, because the syntax is ugly, because Java's C-inherited type prefixes look terrible and are extremely verbose, because Java's type system is pretty bad and finally because the proposal doesn't handle "generic" types, making it completely useless. I also haven't seen any example of typing an instance attribute, the only example involving classes creates a class attribute: class test: $type variable = value $returnType def method(self, $type variable): #do stuff return value
On Sat, Sep 19, 2009 at 4:44 AM, Masklinn <masklinn@masklinn.net> wrote:
As far as I'm concerned, it's a terrible idea. Because it doesn't fit well within Python as a dynamically typed language, because the syntax is ugly, because Java's C-inherited type prefixes look terrible and are extremely verbose, because Java's type system is pretty bad and finally because the proposal doesn't handle "generic" types, making it completely useless.
explain "generic" types
As far as I'm concerned, it's a terrible idea. Because it doesn't fit well within Python as a dynamically typed language, because the syntax is ugly, because Java's C-inherited type prefixes look terrible and are extremely verbose, because Java's type system is pretty bad and finally because the proposal doesn't handle "generic" types, making it completely useless.
explain "generic" types
On 20 Sep 2009, at 00:24 , Dj Gilcrease wrote: On Sat, Sep 19, 2009 at 4:44 AM, Masklinn <masklinn@masklinn.net> wrote: parameterized types: a list of strings (List[String]), a tuple of (int, string) (Tuple[Int, String]), a dict of {Foo:Bar} (Dict[Foo, Bar]) etc… Not having parameterized types means every time you take values out of e.g. a collection you'll have to either use an untyped/"dynamic" variable or cast it to the "right" type (nb: and Python doesn't have casts), and you lose the static guarantee of homogeneity for e.g. lists (with non-generic lists, all your lists are lists of `id` the "dynamic" type).
On Sat, Sep 19, 2009 at 4:40 PM, Masklinn <masklinn@masklinn.net> wrote:
parameterized types: a list of strings (List[String]), a tuple of (int, string) (Tuple[Int, String]), a dict of {Foo:Bar} (Dict[Foo, Bar]) etc…
$dict($type key[, $type value]) $tuple($type value) # lets you specify the type for the tuples values $list($type value) # lets you specify the type for the lists values $set($type value) # lets you specify the type for the sets values $frozenset($type value) # lets you specify the type for the sets values $sets($type value) # lets you specify the type for the sets values $seq($type value) # lets you specify the type for the sequence values These arent what you are looking for?
On Sat, Sep 19, 2009 at 3:16 AM, Steven D'Aprano <steve@pearwood.info> wrote:
On Sat, 19 Sep 2009 06:19:25 pm Dj Gilcrease wrote:
I do not expect this idea to gain much traction but it has been an idea rolling around in my head for a year or two, so I decided to write it all down and see what other thought.
For starters, it's not clear what a static duck is.
Is it a type? Is it a syntax? Is it an extension to existing built-in types? All of the above?
When enabled, does the compiler do the type checking at compile time? Does it happen at runtime? Both? What sort of type checking is done? Pascal-style declarative type checking, or Haskell-style type inference?
Why "static duck"? What does this have to do with duck typing?
Rather than give an implementation of how users can create their own static ducks, it would be better to give some use-cases for where you would use them and what the behaviour is.
The reason I called it static ducks is because you can do "static duck typing". I didnt list file type objects because that means something different to different people. So lets say you want a file like object, any you only care about read, write, and close. class FileTypeCheck(StaticDuckBase): def _get_value(self): return self._value def _set_value(self, value): if not hasattr(value, 'read') or not hasattr(value, 'write') or not hasattr(value, 'close'): raise TypeError("value must be have read, write and close methods") self._value = value staticducks.add('file', FileTypeCheck)
On Sun, 20 Sep 2009 08:21:24 am Dj Gilcrease wrote:
On Sat, Sep 19, 2009 at 3:16 AM, Steven D'Aprano <steve@pearwood.info> wrote:
On Sat, 19 Sep 2009 06:19:25 pm Dj Gilcrease wrote:
I do not expect this idea to gain much traction but it has been an idea rolling around in my head for a year or two, so I decided to write it all down and see what other thought.
For starters, it's not clear what a static duck is.
Is it a type? Is it a syntax? Is it an extension to existing built-in types? All of the above?
When enabled, does the compiler do the type checking at compile time? Does it happen at runtime? Both? What sort of type checking is done? Pascal-style declarative type checking, or Haskell-style type inference?
Why "static duck"? What does this have to do with duck typing?
Rather than give an implementation of how users can create their own static ducks, it would be better to give some use-cases for where you would use them and what the behaviour is.
The reason I called it static ducks is because you can do "static duck typing". I didnt list file type objects because that means something different to different people.
You ignored most of my questions. I'll *guess* what your intention is. You want the compiler to perform declarative type checking at compile time, with no type inference. You're proposing a syntax to declare types, with no implementation at all for how the compiler should actually do that checking. (I'm guessing compile time because you call it *static* ducks, even though you state it should raise TypeError. But you never actually say whether that will be raised when the compiler compiles the code, or when it runs it.) Personally, I'm not convinced that declarative type checking without type inference has enough benefit to be worth the pain of declarations. Nor am I sure that "static duck typing" makes sense in dynamic languages like Python. Consider this example: class Duck(object): def walk(self): return "waddle waddle" def swim(self): return "paddle paddle swim paddle" def quack(self): return "quack quack" class Goose(object): def walk(self): return "waddle waddle flap waddle" def swim(self): return "paddle paddle swim paddle swim" def quack(self): return "honk honk hiss" Is a goose sufficiently duck-like to be treated as a duck? Does it walk like a duck, swim like a duck and quack like a duck? g = Goose() hasattr(g, 'walk') and hasattr(g, 'swim') and hasattr(g, 'quack') -> returns True, so it's a duck Goose.waddle = Goose.walk del Goose.walk hasattr(g, 'walk') -> returns False, so it's not a duck Goose.walk = lambda self: "waddle flap flap waddle waddle" hasattr(g, 'walk') -> returns True, it's a duck again del Goose.walk g.walk = g.waddle hasattr(g, 'walk') -> returns True but only for this instance At *compile time*, how do you know if the goose you receive is sufficiently duck-like or not? I don't think you can. For static checking, it actually gets worse. I can do this: g.__class__ = Duck and totally mess up isinstance() checks as well. Just because something is created as a Duck doesn't mean it will still be a Duck by the time it gets to your function. -- Steven D'Aprano
On Sat, Sep 19, 2009 at 6:00 PM, Steven D'Aprano <steve@pearwood.info> wrote:
You ignored most of my questions. I'll *guess* what your intention is.
You want the compiler to perform declarative type checking at compile time, with no type inference. You're proposing a syntax to declare types, with no implementation at all for how the compiler should actually do that checking.
(I'm guessing compile time because you call it *static* ducks, even though you state it should raise TypeError. But you never actually say whether that will be raised when the compiler compiles the code, or when it runs it.)
Actually I would say it does it at run time because of the requirement that it work along side code that does not use this, both being imported to and importing non static ducked code. In the case it imports code that is not using static ducks it would have to check anything you pass in to a method that is typed or assigned to an attribute that is.
Personally, I'm not convinced that declarative type checking without type inference has enough benefit to be worth the pain of declarations.
Nor am I sure that "static duck typing" makes sense in dynamic languages like Python. Consider this example: [snip] Is a goose sufficiently duck-like to be treated as a duck? Does it walk like a duck, swim like a duck and quack like a duck?
If all you are about are that it can walk swim and quack, then yes. If you care how it walks, swims or quacks, then you would have to have a duck and goose type that just checks if it is an instance of the right class (like my int example). The point of duck typing is that you generally dont care how just that it can. For file like objects you dont care how it reads or writes just that it does
At *compile time*, how do you know if the goose you receive is sufficiently duck-like or not? I don't think you can.
For static checking, it actually gets worse. I can do this:
g.__class__ = Duck
and totally mess up isinstance() checks as well. Just because something is created as a Duck doesn't mean it will still be a Duck by the time it gets to your function.
If it is messing up isinstance then it is going to break any manual type checking the user would try and setup as well, so I see no issue with this
On Sun, 20 Sep 2009 10:33:55 am Dj Gilcrease wrote:
On Sat, Sep 19, 2009 at 6:00 PM, Steven D'Aprano <steve@pearwood.info> wrote:
You ignored most of my questions. I'll *guess* what your intention is.
You want the compiler to perform declarative type checking at compile time, with no type inference. You're proposing a syntax to declare types, with no implementation at all for how the compiler should actually do that checking.
(I'm guessing compile time because you call it *static* ducks, even though you state it should raise TypeError. But you never actually say whether that will be raised when the compiler compiles the code, or when it runs it.)
Actually I would say it does it at run time because of the requirement that it work along side code that does not use this, both being imported to and importing non static ducked code. In the case it imports code that is not using static ducks it would have to check anything you pass in to a method that is typed or assigned to an attribute that is.
I think you're unsure or confused about the different kinds of type systems. I don't think it makes sense to talk about static type checks happening at runtime -- static typing implies that the type of every variable is known at compile time. That's impossible in Python, although of course other languages (like Boo) can have static types with a Python-like syntax. You should read: http://en.wikipedia.org/wiki/Type_system http://www.pphsg.org/cdsmith/types.html It sounds like what you want is a framework for hiding the complexity of runtime type checkers from the developer. I don't think there's any need for new syntax beyond decorators and the type annotations added to Python 3. Type annotations give you a way of declaring types of arguments and return results. Although such declarations are currently ignored by Python, you can write code to enforce them, and decorators give you a neat syntax for applying that code to your functions without having to explicitly include the type checks inside the function body. You can also do the same with metaclasses. You might also be interested in the concept of pre- and post-conditions, taken from Eiffel (and probably other languages as well). Guido van Rossum has given some example metaclasses to perform such Eiffel condition checks: http://www.python.org/doc/essays/metaclasses/ (See the "Real-life Examples" section.) If you haven't already read these, you should: http://www.artima.com/weblogs/viewpost.jsp?thread=85551 http://www.artima.com/weblogs/viewpost.jsp?thread=86641 http://www.artima.com/weblogs/viewpost.jsp?thread=87182 -- Steven D'Aprano
On Mon, Sep 21, 2009 at 6:19 PM, Steven D'Aprano <steve@pearwood.info> wrote:
It sounds like what you want is a framework for hiding the complexity of runtime type checkers from the developer. I don't think there's any need for new syntax beyond decorators and the type annotations added to Python 3. Type annotations give you a way of declaring types of arguments and return results. Although such declarations are currently ignored by Python, you can write code to enforce them, and decorators give you a neat syntax for applying that code to your functions without having to explicitly include the type checks inside the function body. You can also do the same with metaclasses.
Ya but decorators, metaclasses and annotations dont address class attributes, or module level variables, which you should be able to type check on assignment, but you need to do it on use.
Dj Gilcrease wrote:
On Mon, Sep 21, 2009 at 6:19 PM, Steven D'Aprano <steve@pearwood.info> wrote:
It sounds like what you want is a framework for hiding the complexity of runtime type checkers from the developer. I don't think there's any need for new syntax beyond decorators and the type annotations added to Python 3. Type annotations give you a way of declaring types of arguments and return results. Although such declarations are currently ignored by Python, you can write code to enforce them, and decorators give you a neat syntax for applying that code to your functions without having to explicitly include the type checks inside the function body. You can also do the same with metaclasses.
Ya but decorators, metaclasses and annotations dont address class attributes, or module level variables, which you should be able to type check on assignment, but you need to do it on use.
property()?
On Sat, Sep 19, 2009 at 11:19 AM, Dj Gilcrease <digitalxero@gmail.com>wrote: [snip]
Design Goals: The new syntax should * Be simple to read
Personally, I'm -1 on this. Still, if you're already changing the syntax, you don't need the extra punctuation ( '$' in your examples). This could work just as well without them:
Example: $int count = 0
$bool def check($string testValue): return testValue.lower() == "true"
int count = 0 bool def check(string testValue): return testValue.lower() == "true" AFAIK, since today all these cases generate syntax errors, they are pretty unambiguous. Cheers, Imri -- Imri Goldberg -------------------------------------- www.algorithm.co.il/blogs/ -------------------------------------- -- insert signature here ----
Wow! Python that looks a bit like Perl! Larry and Guido reconciled!! I love it!!! +1000 On Sat, Sep 19, 2009 at 12:46 PM, Imri Goldberg <lorgandon@gmail.com> wrote:
On Sat, Sep 19, 2009 at 11:19 AM, Dj Gilcrease <digitalxero@gmail.com> wrote: [snip]
Design Goals: The new syntax should * Be simple to read
Personally, I'm -1 on this. Still, if you're already changing the syntax, you don't need the extra punctuation ( '$' in your examples). This could work just as well without them:
Example: $int count = 0
$bool def check($string testValue): return testValue.lower() == "true"
int count = 0 bool def check(string testValue): return testValue.lower() == "true"
AFAIK, since today all these cases generate syntax errors, they are pretty unambiguous.
Cheers, Imri
-- Imri Goldberg -------------------------------------- www.algorithm.co.il/blogs/ -------------------------------------- -- insert signature here ----
_______________________________________________ Python-ideas mailing list Python-ideas@python.org http://mail.python.org/mailman/listinfo/python-ideas
-- Gerald Britton
On Sat, Sep 19, 2009 at 10:46 AM, Imri Goldberg <lorgandon@gmail.com> wrote:
Personally, I'm -1 on this. Still, if you're already changing the syntax, you don't need the extra punctuation ( '$' in your examples). This could work just as well without them:
The reason I picked the $ is because I think it would be harder to change the syntax to support dynamically added types without some "start type" token, but I may be wrong in that case since I suck at language syntax generation
Dj Gilcrease wrote:
Design Goals: The new syntax should * Be simple to read * Make it obvious what is happening; at the very least it should be obvious that new users can safely ignore it when writing their own code * Allow future compilers to optimize for Static Typing. * Work within a function or method definition to ensure a passed variable is the proper type * Allow Functions/Methods return values to be typed and checked * Raise an TypeError exception when the variable is set to something improper, or the function/method tries to return an improper value
My impression is that all the above could be done (at least by alternative implementations) with current 3.x function signatures. Where do you think they fail?
Issues: If this PEP is implemented it may conflict with PEP 362 (Function Signature Object)
Dj Gilcrease wrote:
I do not expect this idea to gain much traction but it has been an idea rolling around in my head for a year or two, so I decided to write it all down and see what other thought.
Abstract: Python does not currently support static typing of variables, which is something I like, but there are times it would be nice to have static typing for variables, or method/function return values.
I am working on a somewhat different approach to this problem. (For sufficiently large values of 'somwhat different'.) A while back, I came to the conclusion that there was still much to be learned about static typing, and that the existing languages that support static typing were misusing it - that is, in most languages static typing is used to enforce consistency (the advantage of which has been much debated) as opposed to making the language easier and more expressive. Despite my fondness for Python, I realized that I didn't want something that would merely be a layer on top of Python syntax - the decision to incorporate static types would impact so many of the design choices of the language that it would end up being a fundamentally different language. It was only after I discovered the existence of the LLVM project that I realized that I could actually build the language that I had been designing in my head. So I set out to build that language, and along the way I would fix a number of other issues in Python, as well as the many issues I have with Java, C++, C#, D, Ruby, and so on. And also incorporate a few of the ideas which have been suggested on this list and others. In any case, it's two years later and I am still working on the compiler. :) But I am making a lot of progress and it's slowly evolving into something that I think is quite cool. I'm not the first person to attempt this, so if you want to try a language that is statically typed, but inspired by Python, then I suggest checking out Boo or Scala. -- Talin
On Sat, Sep 19, 2009 at 8:29 PM, Talin <talin@acm.org> wrote:
I'm not the first person to attempt this, so if you want to try a language that is statically typed, but inspired by Python, then I suggest checking out Boo or Scala.
I dont want Static typing as it exists in Java or C or whatever other statically type langue that exists. I think of what I am trying to accomplish as an easier way of having syntax for type checking that does not involve having to do isinstance or hasattr checks in every place you want to validate the type. You just set the type using a decorator style syntax and the type checking is done automatically for you, which will reduce code repetition, especially in getter/setter methods of properties.
On Sat, Sep 19, 2009 at 8:43 PM, Dj Gilcrease <digitalxero@gmail.com> wrote:
I dont want Static typing as it exists in Java or C or whatever other statically type langue that exists.
I think a better name might be Strong Ducks, so instead of a Strongly Typed Language you have a Strongly Duck Typed Option, which is just an easier way of validating that what you are getting or setting meets your needs in a way that is more flexible then an interface ala Java or even an Abstract Base Class.
I don't quite understand what you are trying to solve. Here's a related problem: One of the issues with duck typing is that something might look sort of like a duck but isn't really and it would be nice to make it easy to avoid using an object in a "half-baked" manner: def playWithDuck(d): d.walk() d.quack() if someone calls playWithDuck(dog) then the dog's going to get walked before trying to make the dog quack fails. I'd like to be able to avoid that. I could write: def playWithDuck(d): d.quack # raises AttributeError if can't quack d.walk() d.quack() but of course that doesn't check that d.quack is a function or even has the right kind of signature. And I can write def playWithDuck(d): if not isinstance(d, Duck): raise TypeError("need a Duck") ... which has it's own problems (I don't need a Duck; I just need something that walks like a duck and quacks like a duck). Is this the problem you are trying to solve? Or something else? --- Bruce
On Sat, Sep 19, 2009 at 10:21 PM, Bruce Leban <bruce@leapyear.org> wrote:
I don't quite understand what you are trying to solve. Here's a related problem: One of the issues with duck typing is that something might look sort of like a duck but isn't really and it would be nice to make it easy to avoid using an object in a "half-baked" manner:
def playWithDuck(d): d.walk() d.quack()
if someone calls playWithDuck(dog) then the dog's going to get walked before trying to make the dog quack fails. I'd like to be able to avoid that. I could write:
def playWithDuck(d): d.quack # raises AttributeError if can't quack d.walk() d.quack()
but of course that doesn't check that d.quack is a function or even has the right kind of signature. And I can write
def playWithDuck(d): if not isinstance(d, Duck): raise TypeError("need a Duck") ...
which has it's own problems (I don't need a Duck; I just need something that walks like a duck and quacks like a duck).
Is this the problem you are trying to solve? Or something else?
This is a good description of an issue I would like to solve with this.
Bruce Leban wrote:
but of course that doesn't check that d.quack is a function or even has the right kind of signature. And I can write
def playWithDuck(d): if not isinstance(d, Duck): raise TypeError("need a Duck") ...
which has it's own problems (I don't need a Duck; I just need something that walks like a duck and quacks like a duck).
Actually, so long as Duck is defined as an Abstract Base Class rather than an ordinary type, then the above does solve your problem. If someone wants to declare that their type does indeed walk and quack like a duck, they can just call Duck.register(my_type). Regarding static typing with type inference, something to look at would be the repurposing of the auto keyword in C++0x (soon to be known as C++1x, since the committee has declared the updated standard won't be getting released this year). Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia ---------------------------------------------------------------
On 20 Sep 2009, at 06:21 , Bruce Leban wrote: I don't quite understand what you are trying to solve. Here's a related
problem: One of the issues with duck typing is that something might look sort of like a duck but isn't really and it would be nice to make it easy to avoid using an object in a "half-baked" manner:
def playWithDuck(d): d.walk() d.quack()
if someone calls playWithDuck(dog) then the dog's going to get walked before trying to make the dog quack fails.
Note that with a structural type system (that of OCaml's objects for instance) this will work, the `playWithDuck` function will be inferred to take any subtype of < walk : unit; duck : unit > (or something like that) (basically, any object with a `walk` and a `quack` method (both returning nothing) will work).
I was trying to think how a decorator @strict_duck_typing could be implemented to solve the issue Bruce Leban described. The more I think about it, the harder I think it is to implement. I wanted to do something along the lines of: def parameters_from_signature(function, args, kwargs): "Translate a generic function call to the function's parameters by name" argnames, varargs, keywords, defaults = inspect.getargspec(function) args_and_kwargs = kwargs.copy() names_and_args = zip(argnames, args) args_and_kwargs.update(names_and_args) if varargs is not None: args_and_kwargs[varargs] = args[len(argnames):] return args_and_kwargs def strict_duck_typing(function): attr_dict = attributes_used_by_function(function) def verify_and_run(*args, **kwargs): called_with = parameters_from_signature(function, args, kwargs) for parameter, attributes_needed in attr_dict.items(): for attr in attributes_needed: if not hasattr(called_with[parameter], attr): raise TypeError("Parameter '%s' given doesn't have '%s' attribute/method." % (parameter, attr)) function(*args, **kwargs) Of course the big enchilada is the function 'attributes_used_by_function' which I left out because it has to do some insane things. I was thinking of using ast.parse(inspect.getsource(function)) and then: 1. stepping into each function call which involves the function parameters, perhaps repeating the ast.parse/inspect.getsource combo. 2. collecting all the methods and attributes accessed. 3. getattr/setattr/hasattr need to be simulated or handled 4. return a dictionary of { parameter_name: attributes_needed_set } And even after this crazy piece of work there are some limitations ie: 1. C functions wouldn't be inspected, which is a tragedy, ie len(), iter(), etc have to be especially treated... 2. dynamically generated attributes and attribute names will always break this decorator. 3. performance issues 4. probably more things i didn't think of... So I like the idea of strict duck typing, but it's gonna take more than one mailing list reply for me to write a POC :) On Sun, Sep 20, 2009 at 12:56 PM, Masklinn <masklinn@masklinn.net> wrote:
On 20 Sep 2009, at 06:21 , Bruce Leban wrote: I don't quite understand what you are trying to solve. Here's a related
problem: One of the issues with duck typing is that something might look sort of like a duck but isn't really and it would be nice to make it easy to avoid using an object in a "half-baked" manner:
def playWithDuck(d): d.walk() d.quack()
if someone calls playWithDuck(dog) then the dog's going to get walked before trying to make the dog quack fails.
Note that with a structural type system (that of OCaml's objects for instance) this will work, the `playWithDuck` function will be inferred to take any subtype of < walk : unit; duck : unit > (or something like that) (basically, any object with a `walk` and a `quack` method (both returning nothing) will work).
_______________________________________________ Python-ideas mailing list Python-ideas@python.org http://mail.python.org/mailman/listinfo/python-ideas
Dj Gilcrease wrote:
I think of what I am trying to accomplish as an easier way of having syntax for type checking that does not involve having to do isinstance or hasattr checks in every place you want to validate the type.
A potential problem with this is that if you make it *too* easy to write type checks, you're likely to end up with inefficiencies due to types being checked a lot more often than they really need to be. There's a school of thought that expensive operations shouldn't be hidden behind syntax that makes them appear deceptively cheap. On that basis, since there is some cost to doing a type check, it could be argued that you should have to do a bit of work in order to write one. -- Greg
On Sun, Sep 20, 2009 at 1:34 AM, Greg Ewing <greg.ewing@canterbury.ac.nz> wrote:
A potential problem with this is that if you make it *too* easy to write type checks, you're likely to end up with inefficiencies due to types being checked a lot more often than they really need to be.
True, which is why I figured it should be off by default and need either a command line option to be enabled globally or some form of activation at the top of the file to be enabled for a specific module. Doing it this way will make it so the dev needs to decide if they want to incur the performance penalty for type safety. I figure it would be used most often via the command line option for testing to ensure an app or library is type safe within itself and leave it to people that use it to make sure they are following the rules. The other common place I see it being used is within an IDE to mark code as an error that fails the specified type. Since you work on Pyrex and one of the potential use cases I listed was for python to c compilers is there anything you would change about my specified syntax and usage to work better for Pyrex?
Dj Gilcrease wrote:
Since you work on Pyrex and one of the potential use cases I listed was for python to c compilers is there anything you would change about my specified syntax and usage to work better for Pyrex?
Well, Pyrex already has its own syntax for declaring types (essentially adopted from C) so it doesn't really need another one. Also, there's no expectation that Pyrex will be able to compile Python code in general, so it doesn't matter to Pyrex what type declaration syntax, if any, gets use in Python. You might like to talk to the Cython crowd -- being able to compile pure Python code *is* one of their goals. If I were designing a language from scratch now with type declarations, I would try to arrange it so that the types come *after* the names being declared, as in Pascal, because that makes it easier to scan down a list of declarations looking for the definition of a name. Also I don't particularly care for your use of $. It looks out of place amongst the rest of the Python language. -- Greg
Talin wrote:
the existing languages that support static typing were misusing it - that is, in most languages static typing is used to enforce consistency (the advantage of which has been much debated) as opposed to making the language easier and more expressive.
That's one side of it. The other side is giving the compiler enough information about what you're trying to do that it can generate safe and efficient code to do it.
So I set out to build that language, and along the way I would fix a number of other issues in Python, as well as the many issues I have with Java, C++, C#, D, Ruby, and so on. And also incorporate a few of the ideas which have been suggested on this list and others.
This sounds interesting. Would you mind sharing some of the ideas you have about how to improve on the way previous languages have used static typing? Also I notice that all the languages you mention are imperative ones. Have you looked at languages such as Haskell which use type inferencing? Is there anything we can learn from that camp? (My experiences with type inferencing suggest that it's fine up to a point, but you really need to insert explicit type declarations at some key points, otherwise it becomes too difficult to track down where type errors are coming from.) I've also been grappling with static vs. dynamic typing issues to some extent while developing Pyrex. Having an essentially dynamically typed language that allows static declarations where desired for efficiency seems to be a very powerful idea. Cython seems to be heading in that direction with the ability to add supplemental declarations to otherwise pure Python code. -- Greg
I tried to read most of the thread, but I'm still not sure about the exact meaning of the proposal. Here is how I understand it. There are two ways to add strong typing to the language. One is called "static typing", and it's done before you generate a bytecode, another, "dynamic/run-time typing" is done at run-time. Static typing is unlikely to work in Python. Suppose I do $list a = ['string', 5+6] $int index = some_very_complicated_calculation() ??? a[index] # Compiler cannot know if this is string, int or IndexError. or I could try accessing globals(name) or sys.module[name].attribute -- compile-time check is impossible.
From what I read I think you suggest to add run-time typing to the language. That is partly possible now with decorators and the annotations syntax -- you might want to check that out -- but how useful is it really? The very fact that X is integer and Y is integer doesn't mean that X + Y or X * Y always makes sense.
There was a very good question on StackOverflow that dealt with typing: http://stackoverflow.com/questions/1275646/python-3-and-static-typing/127658... My detailed opinion and links can be found there in the answer (the accepted one). Ilya. On Sat, Sep 19, 2009 at 12:19 PM, Dj Gilcrease <digitalxero@gmail.com> wrote:
I do not expect this idea to gain much traction but it has been an idea rolling around in my head for a year or two, so I decided to write it all down and see what other thought.
Abstract: Python does not currently support static typing of variables, which is something I like, but there are times it would be nice to have static typing for variables, or method/function return values.
Static Ducks should be able to run along side or imported to code that does not use Static Ducks. Actual runtime enforcement of Static Ducks should be off by default and require activation either via the command line or at the top of a file (similar to the __future__ requirement) where it would affect only that file (and any Static Ducks imported to it)
Design Goals: The new syntax should * Be simple to read * Make it obvious what is happening; at the very least it should be obvious that new users can safely ignore it when writing their own code * Allow future compilers to optimize for Static Typing. * Work within a function or method definition to ensure a passed variable is the proper type * Allow Functions/Methods return values to be typed and checked * Raise an TypeError exception when the variable is set to something improper, or the function/method tries to return an improper value
Issues: If this PEP is implemented it may conflict with PEP 362 (Function Signature Object)
Use Cases: Python to C compilers could be enhanced by allowing static ducks. IDE's code complete could be enhanced by having static ducks available IDE's issues prediction could be enhanced to detect type issues for code that uses static ducks (Like any static typed language)
Syntax Idea: """$type variable = value
$returnType def function($type variable): #do stuff return value
$returnType def function($type variable): #do stuff return value
class test: $type variable = value
$returnType def method(self, $type variable): #do stuff return value"""
The reason I selected $type is because I couldn't think of anything else that $ was used for and I wanted a syntax similar to Decorators and similar to other statically typed languages.
All types allow None or their proper type when setting, this so people can have typed variables that can be "undefined" for checking
Example: $int count = 0
$bool def check($string testValue): return testValue.lower() == "true"
class test: $string _name = None
$string def get_name(self): return self._name
def set_name(self, $string name): self._name = name
Usage Details: When a variable has been statically type, any time it is set later its type needs to be verified. I see this working in a similar way to how properties work. Also using this style would allow people to create their own static ducks.
"""psudo-code class StaticDuckBase(object): _value = None
class IntTypeClass(StaticDuckBase): def _get_value(self): return self._value
def _set_value(self, val): if isinstance(val, (int, type(None))): self._value = val else: try: val = int(val) self._value = val except: raise TypeError("Expected int, got " + str(type(val)) + " instead!")
value = property(_get_value, _set_value, None)
class MyTypeClass(StaticDuckBase): def _get_value(self): return self._value
def _set_value(self, val): if isinstance(val, MyType)): self._value = val else: raise TypeError("Expected MyType, got " + str(type(val)) + " instead!")
value = property(_get_value, _set_value, None)
staticducks.add('mytype', MyTypeClass) """
Though there will need to be some way to check if a variable is statically typed so that when you do $int count = 0 then later count = 5 it uses the static typing. Also if no static duck is specified it should revert to nonstatic but emit a warning that is only show when run with the -W option
Type List: Base Types: $int $float $bool $string $tuple $namedtuple $list $set $frozenset $dict $byte $bytearray $memoryview $nonstatic # This means treat it as if it were not statically typed
Composite type $bytes -> $byte | $bytearray $number -> $int | $float | Decimal $seq -> $tuple | $list | $set | $frozenset | $namedtuple $sets -> $set | $frozenset
Special Cases #lets you require a specific type for keys and values $dict($type key[, $type value]) """eg $dict($int, $string) tmp = {} # creates a dict that requires ints as keys and strings as values $dict($nonstatic, $bool) tmp = {} # creates a dict that requires values to be bool, but keys can be anything """
$tuple($type value) # lets you specify the type for the tuples values $list($type value) # lets you specify the type for the lists values $set($type value) # lets you specify the type for the sets values $frozenset($type value) # lets you specify the type for the sets values $sets($type value) # lets you specify the type for the sets values $seq($type value) # lets you specify the type for the sequence values
$string(encoding="UTF-8", normalized=False) $normalized # This would be equiv of doing $string(normalized=True) $normalized(encoding="UTF-8") _______________________________________________ Python-ideas mailing list Python-ideas@python.org http://mail.python.org/mailman/listinfo/python-ideas
ilya wrote:
I tried to read most of the thread, but I'm still not sure about the exact meaning of the proposal. Here is how I understand it.
There are two ways to add strong typing to the language. One is called "static typing", and it's done before you generate a bytecode, another, "dynamic/run-time typing" is done at run-time.
Python already has strong dynamic typing. strong-vs-weak and static-vs-dynamic are orthogonal attributes of type systems. Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia ---------------------------------------------------------------
ilya wrote:
I tried to read most of the thread, but I'm still not sure about the exact meaning of the proposal. Here is how I understand it.
There are two ways to add strong typing to the language. One is called "static typing", and it's done before you generate a bytecode, another, "dynamic/run-time typing" is done at run-time.
Python already has strong dynamic typing. strong-vs-weak and static-vs-dynamic are orthogonal attributes of type systems. The first part is usually considered true, the second part is more difficult to handle. The issue being that "strong typing/weak typing" isn't formally defined at all, an people tend to make "their own" definition of it to fit their preconceptions: a few years ago, Mark- Jason Dominus found (at least) 8 different definitions of the concept ( http://groups.google.com/group/comp.lang.perl.moderated/tree/browse_frm/thread/e2e153d2ad7380c5/73d99bd8d5d16d8a?rnum=1&_done=%2Fgroup%2Fcomp.lang.perl.moderated%2Fbrowse_frm%2Fthread%2Fe2e153d2ad7380c5%2F73d99bd8d5d16d8a%3Ftvc%3D1%26#doc_89b5f256ea7bfadb ) and B.C.Pierce [TAPL] gave up on the subject altogether after a
On 21 Sep 2009, at 14:27 , Nick Coghlan wrote: pair of weeks of research. The mere idea of talking about "strong typing" without precisely defining what you mean by that is therefore bound to fail (as for one person Tcl will be strongly typed, meanwhile for another one anything falling short of *ML or Haskell is weakly typed). The static/dynamic typing axis is better defined (though there's a lot of blurring, it's a continuous path rather than a binary proposition).
Masklinn wrote:
On 21 Sep 2009, at 14:27 , Nick Coghlan wrote:
ilya wrote:
I tried to read most of the thread, but I'm still not sure about the exact meaning of the proposal. Here is how I understand it.
There are two ways to add strong typing to the language. One is called "static typing", and it's done before you generate a bytecode, another, "dynamic/run-time typing" is done at run-time.
Python already has strong dynamic typing. strong-vs-weak and static-vs-dynamic are orthogonal attributes of type systems. The first part is usually considered true, the second part is more difficult to handle. The issue being that "strong typing/weak typing" isn't formally defined at all, an people tend to make "their own" definition of it to fit their preconceptions: a few years ago, Mark-Jason Dominus found (at least) 8 different definitions of the concept ( http://groups.google.com/group/comp.lang.perl.moderated/tree/browse_frm/thread/e2e153d2ad7380c5/73d99bd8d5d16d8a?rnum=1&_done=%2Fgroup%2Fcomp.lang.perl.moderated%2Fbrowse_frm%2Fthread%2Fe2e153d2ad7380c5%2F73d99bd8d5d16d8a%3Ftvc%3D1%26#doc_89b5f256ea7bfadb ) and B.C.Pierce [TAPL] gave up on the subject altogether after a pair of weeks of research. The mere idea of talking about "strong typing" without precisely defining what you mean by that is therefore bound to fail (as for one person Tcl will be strongly typed, meanwhile for another one anything falling short of *ML or Haskell is weakly typed).
The static/dynamic typing axis is better defined (though there's a lot of blurring, it's a continuous path rather than a binary proposition).
I know of one language which is weakly typed: BCPL. It's only type is the bit pattern. It's the function or operator which interprets the bits as representing a certain value.
On Mon, 21 Sep 2009 11:55:57 pm MRAB wrote:
I know of one language which is weakly typed: BCPL. It's only type is the bit pattern. It's the function or operator which interprets the bits as representing a certain value.
That would make BCPL an untyped language, like assembly. If the language has no types, it can't be either weakly or strongly typed. Weak and string typing is a matter of degree. Most languages are weakly typed to some extent, for instance Python will automatically coerce various number types so you can add integers to floats etc., as will Pascal. Numeric coercion is so widespread that most people consider it an exception to weak typing: if all the language coerces are numeric types, then it's still strongly typed. The classic test for weak typing versus strong typing is operations on mixed integers and strings. Can you add or concatenate strings to integers without an explicit conversion? Perl is weakly typed: $ perl -e 'print "2"+2; print "\n";' 4 $ perl -e 'print "2".2; print "\n";' 22 PHP and (I think) Javascript will do the same. It's been some years since I've used it, but I recall Apple's Hypertalk behaved similarly. I think you could say 2&"2" (returns "22") and 2+"2" (returns 4). Hypertalk is no longer supported, but I expect Apple's current generation scripting language, AppleScript, would probably be the same. -- Steven D'Aprano
Steven D'Aprano wrote:
On Mon, 21 Sep 2009 11:55:57 pm MRAB wrote:
I know of one language which is weakly typed: BCPL. It's only type is the bit pattern. It's the function or operator which interprets the bits as representing a certain value.
That would make BCPL an untyped language, like assembly. If the language has no types, it can't be either weakly or strongly typed.
Weak and string typing is a matter of degree. Most languages are weakly typed to some extent, for instance Python will automatically coerce various number types so you can add integers to floats etc., as will Pascal. Numeric coercion is so widespread that most people consider it an exception to weak typing: if all the language coerces are numeric types, then it's still strongly typed.
The classic test for weak typing versus strong typing is operations on mixed integers and strings. Can you add or concatenate strings to integers without an explicit conversion? Perl is weakly typed:
$ perl -e 'print "2"+2; print "\n";' 4 $ perl -e 'print "2".2; print "\n";' 22
PHP and (I think) Javascript will do the same.
It's been some years since I've used it, but I recall Apple's Hypertalk behaved similarly. I think you could say 2&"2" (returns "22") and 2+"2" (returns 4). Hypertalk is no longer supported, but I expect Apple's current generation scripting language, AppleScript, would probably be the same.
I read that someone re-wrote a Perl script in Python and found that a process that it called sometimes returned "ERROR" instead of a numeric string, which Perl would just coerce to 0, thus hiding the error! The Icon language also performs automatic coercion, but invalid strings cause a runtime error (unfortunately the language doesn't support catchable exceptions, or at least didn't in the last version I know of). Icon also shows the disadvantage of automatic coercions: there's an operator for addition, one for string concatenation, and one for list concatenation. If you wanted to add sets (not just charsets), you'd need yet another operator. In Python you can just reuse them and let the classes decide what they do! :-)
Unfortunately Excel, probably the most widely used end-user programming environment in the world, allows you to both concatenate (&) and add strings and numbers. Interestingly the formula language is also a functional programming language (expressions only) where control flow is determined by dependencies between expressions. Michael -- http://www.ironpythoninaction.com On 22 Sep 2009, at 00:18, Steven D'Aprano <steve@pearwood.info> wrote:
On Mon, 21 Sep 2009 11:55:57 pm MRAB wrote:
I know of one language which is weakly typed: BCPL. It's only type is the bit pattern. It's the function or operator which interprets the bits as representing a certain value.
That would make BCPL an untyped language, like assembly. If the language has no types, it can't be either weakly or strongly typed.
Weak and string typing is a matter of degree. Most languages are weakly typed to some extent, for instance Python will automatically coerce various number types so you can add integers to floats etc., as will Pascal. Numeric coercion is so widespread that most people consider it an exception to weak typing: if all the language coerces are numeric types, then it's still strongly typed.
The classic test for weak typing versus strong typing is operations on mixed integers and strings. Can you add or concatenate strings to integers without an explicit conversion? Perl is weakly typed:
$ perl -e 'print "2"+2; print "\n";' 4 $ perl -e 'print "2".2; print "\n";' 22
PHP and (I think) Javascript will do the same.
It's been some years since I've used it, but I recall Apple's Hypertalk behaved similarly. I think you could say 2&"2" (returns "22") and 2+"2" (returns 4). Hypertalk is no longer supported, but I expect Apple's current generation scripting language, AppleScript, would probably be the same.
-- Steven D'Aprano _______________________________________________ Python-ideas mailing list Python-ideas@python.org http://mail.python.org/mailman/listinfo/python-ideas
On 09/22/2009 01:18 AM, Steven D'Aprano wrote:
On Mon, 21 Sep 2009 11:55:57 pm MRAB wrote:
I know of one language which is weakly typed: BCPL. It's only type is the bit pattern. It's the function or operator which interprets the bits as representing a certain value.
That would make BCPL an untyped language, like assembly. If the language has no types, it can't be either weakly or strongly typed.
Weak and string typing is a matter of degree. Most languages are weakly typed to some extent, for instance Python will automatically coerce various number types so you can add integers to floats etc., as will Pascal. Numeric coercion is so widespread that most people consider it an exception to weak typing: if all the language coerces are numeric types, then it's still strongly typed.
The classic test for weak typing versus strong typing is operations on mixed integers and strings. Can you add or concatenate strings to integers without an explicit conversion? Perl is weakly typed:
$ perl -e 'print "2"+2; print "\n";' 4 $ perl -e 'print "2".2; print "\n";' 22
Written from memory, C++: #include <string> #include <cstdio> int operator + (const std::string& lhs, int rhs) { int i = 0; std::sscanf(lhs.c_str(), "%d", &i); return i + rhs; } int main() { std::string s = "2"; std::printf("%d\n", s + 2); return 0; } Prints: 4 I don't think this is a valid test to determine how a language is typed. Ok, C++ is more or less weakly typed (for other reasons), but I think you could write something similar in C#, too. And C# is strongly typed.
PHP and (I think) Javascript will do the same.
It's been some years since I've used it, but I recall Apple's Hypertalk behaved similarly. I think you could say 2&"2" (returns "22") and 2+"2" (returns 4). Hypertalk is no longer supported, but I expect Apple's current generation scripting language, AppleScript, would probably be the same.
On Tue, 22 Sep 2009 01:05:41 pm Mathias Panzenböck wrote:
I don't think this is a valid test to determine how a language is typed. Ok, C++ is more or less weakly typed (for other reasons), but I think you could write something similar in C#, too. And C# is strongly typed.
Weak and strong typing are a matter of degree -- there's no definitive test for "weak" vs "strong" typing, only degrees of weakness. The classic test is whether you can add strings and ints together, but of course that's only one possible test out of many. I can imagine a language which requires explicit conversions between ints and strings, while implicitly converting or casting nearly every other data type! According to Wikipedia, C# is strongly typed. The only implicit conversions are "safe" conversions, such as widening integer types (e.g. convert 32-bit ints into 64-bit ints, but not the other way), and some implicit conversions between derived types and their base types. The rules are relaxed a little for the int literal 0. I assume that, like most languages, it allows mixed int/float arithmetic. This is quite similar to Python, which also implicitly widens ints to long ints. Arguably Python is weaker than C#, as Python accepts any object in truth concepts, while C# requires an actual bool type. I'd be surprised if C# implicitly converts strings to ints, but if it did, that would be a good example showing that the strength of the type system is not a one dimensional quantity. -- Steven D'Aprano
On 22 Sep 2009, at 15:16 , Steven D'Aprano wrote:
On Tue, 22 Sep 2009 01:05:41 pm Mathias Panzenböck wrote:
I don't think this is a valid test to determine how a language is typed. Ok, C++ is more or less weakly typed (for other reasons), but I think you could write something similar in C#, too. And C# is strongly typed.
Weak and strong typing are a matter of degree -- there's no definitive test for "weak" vs "strong" typing, only degrees of weakness. The classic test is whether you can add strings and ints together, but of course that's only one possible test out of many. And it's a pretty bad one to boot: both Java and C# allow adding strings and ints (whether it's `3 + "5"` or `"5" + 3`) (in fact they allow adding *anything* to a string), but the operation is well defined: convert any non-string involved to a string (via #toString ()/.ToString()) and concatenate.
According to Wikipedia, C# is strongly typed. The only implicit conversions are "safe" conversions, such as widening integer types (e.g. convert 32-bit ints into 64-bit ints, but not the other way), and some implicit conversions between derived types and their base types. The rules are relaxed a little for the int literal 0. I assume that, like most languages, it allows mixed int/float arithmetic.
See above: C#, much like Java, also allows concatenating anything to strings, and implicitly convert non-strings to strings.
On Wed, 23 Sep 2009 12:25:32 am Masklinn wrote:
On 22 Sep 2009, at 15:16 , Steven D'Aprano wrote:
On Tue, 22 Sep 2009 01:05:41 pm Mathias Panzenböck wrote:
I don't think this is a valid test to determine how a language is typed. Ok, C++ is more or less weakly typed (for other reasons), but I think you could write something similar in C#, too. And C# is strongly typed.
Weak and strong typing are a matter of degree -- there's no definitive test for "weak" vs "strong" typing, only degrees of weakness. The classic test is whether you can add strings and ints together, but of course that's only one possible test out of many.
And it's a pretty bad one to boot: both Java and C# allow adding strings and ints (whether it's `3 + "5"` or `"5" + 3`) (in fact they allow adding *anything* to a string), but the operation is well defined: convert any non-string involved to a string (via #toString ()/.ToString()) and concatenate.
I don't see why you say it's a bad test. To me, it's a good test, and Java and C# pass it. If you're only criterion is that an operation is well-defined, then "weak typing" becomes meaningless: I could define addition of dicts and strings to be the sum of the length of the dict with the number of hyphens in the string, and declare that {'foo':'a', 'bar':'b'} + "12-34-56-78-90" returns 6, and by your criterion my language would be strongly typed. I think that makes a mockery of the whole concept. [...]
See above: C#, much like Java, also allows concatenating anything to strings, and implicitly convert non-strings to strings.
Which hints that (at least when it comes to strings) C# and Java are weakly typed and that people consider them "strongly typed" is a triumph of marketing over reality. For any typed language, you ask how the language deals with operations on mixed types. If you have to explicitly convert the values to a common type, the language is strongly typed. If the language implicitly does the conversion for you, it is weakly typed. If, as is usually the case, the language does some conversions automatically, and others requires you to do explicitly, then the language combines some strong typing with some weak typing, and it becomes a matter of degree whether you call it strongly or weakly typed. If we insist in sticking every language in a binary state of "weak" or "strong", then we need a heuristic to decide. The heuristic in common use is to allow implicit numeric coercions in strongly typed languages, but usually not to allow implicit string to int conversions. This heuristic is not arbitrary. Automatically converting ints to floats is mathematically reasonable, because we consider e.g. 3 and 3.0 to be the same number. But automatically converting strings to ints is somewhat dubious. Although the intent of "1"+1 may be obvious, what is the intent of "foo"+1? Should "foo" convert to 0, or should "foo" be treated equivalent to a 24-bit integer, or what? There's no objective reason for preferring one behaviour over another. The same applies for "1"&123 -- should we treat the int 123 as the string "123", or the string "\01\02\03", or what? Of course a language designer is free to arbitrarily choose one behaviour over the other, but that is weak typing. "Strong typing" carries connotations of strength and security, and "weak typing" sounds soft and risky, but neither of these are necessarily correct. Perl is weakly typed but it's very hard to cause it to crash, while C++ is strongly typed but easy to cause it to core-dump. Neither strategy is objectively better than the other in *all* cases, although in my opinion strong typing is probably *usually* better. -- Steven D'Aprano
On 22 Sep 2009, at 17:46 , Steven D'Aprano wrote:
On Wed, 23 Sep 2009 12:25:32 am Masklinn wrote:
On 22 Sep 2009, at 15:16 , Steven D'Aprano wrote:
On Tue, 22 Sep 2009 01:05:41 pm Mathias Panzenböck wrote:
I don't think this is a valid test to determine how a language is typed. Ok, C++ is more or less weakly typed (for other reasons), but I think you could write something similar in C#, too. And C# is strongly typed.
Weak and strong typing are a matter of degree -- there's no definitive test for "weak" vs "strong" typing, only degrees of weakness. The classic test is whether you can add strings and ints together, but of course that's only one possible test out of many.
And it's a pretty bad one to boot: both Java and C# allow adding strings and ints (whether it's `3 + "5"` or `"5" + 3`) (in fact they allow adding *anything* to a string), but the operation is well defined: convert any non-string involved to a string (via #toString ()/.ToString()) and concatenate.
I don't see why you say it's a bad test. To me, it's a good test, and Java and C# pass it.
Uh no, by your criterion they fail it: both java and C# do add strings and integers without peeping.
If you're only criterion is that an operation is well-defined, then "weak typing" becomes meaningless: I could define addition of dicts and strings to be the sum of the length of the dict with the number of hyphens in the string, and declare that
{'foo':'a', 'bar':'b'} + "12-34-56-78-90"
returns 6, and by your criterion my language would be strongly typed. I think that makes a mockery of the whole concept. I don't think I defined any criterion of strong/weak typing. As far as I'm concerned, and as I've already mentioned in this thread, the whole weak/strong axis is meaningless and laughable.
This heuristic is not arbitrary. Of course it is.
Automatically converting ints to floats is mathematically reasonable, because we consider e.g. 3 and 3.0 to be the same number. Do we? Given 3/2 and 3.0/2 don't necessarily give the same answer (some languages don't even consider the first operation valid), I'm not sure we do.
Perl is weakly typed but it's very hard to cause it to crash, See the link I previously gave, you might consider Perl weakly typed, not everybody does.
while C++ is strongly typed but easy to cause it to core-dump. See my response to your previous declaration.
On Wed, 23 Sep 2009 02:35:49 am Masklinn wrote:
On 22 Sep 2009, at 17:46 , Steven D'Aprano wrote:
On Wed, 23 Sep 2009 12:25:32 am Masklinn wrote:
On 22 Sep 2009, at 15:16 , Steven D'Aprano wrote:
On Tue, 22 Sep 2009 01:05:41 pm Mathias Panzenböck wrote:
I don't think this is a valid test to determine how a language is typed. Ok, C++ is more or less weakly typed (for other reasons), but I think you could write something similar in C#, too. And C# is strongly typed.
Weak and strong typing are a matter of degree -- there's no definitive test for "weak" vs "strong" typing, only degrees of weakness. The classic test is whether you can add strings and ints together, but of course that's only one possible test out of many.
And it's a pretty bad one to boot: both Java and C# allow adding strings and ints (whether it's `3 + "5"` or `"5" + 3`) (in fact they allow adding *anything* to a string), but the operation is well defined: convert any non-string involved to a string (via #toString ()/.ToString()) and concatenate.
I don't see why you say it's a bad test. To me, it's a good test, and Java and C# pass it.
Uh no, by your criterion they fail it: both java and C# do add strings and integers without peeping.
What are you talking about? Using Python syntax, we might write: assert "2"+2 == 4 This test will FAIL for Python, Pascal and other strongly typed languages, and PASS for weakly typed languages. (For some languages, like Pascal, you can't even compile the test!)
If you're only criterion is that an operation is well-defined, then "weak typing" becomes meaningless...
I don't think I defined any criterion of strong/weak typing.
You conceded that C# adds strings and ints, but disputed that this fact makes C# weakly typed on the basis that (I quote) "the operation is well defined". There's nothing about the definition of weakly typed languages that requires the implicit conversions to be random, arbitrary or badly defined, ONLY that they are implicit, and by that definition, C# is weakly typed with regard to strings+ints.
As far as I'm concerned, and as I've already mentioned in this thread, the whole weak/strong axis is meaningless and laughable.
I agree that treating weak/strong as a binary state is an over-simplification, but a weak/strong axis is perfectly reasonable. Count the number of possible mixed-type operations permitted by the language (for simplicity, limit it to built-in or fundamental types). What percentage of them succeed without explicit casts or conversions? If that percentage is 0%, then the language is entirely strong. If it is 100%, then the language is entirely weak. In practice, languages will likely fall somewhere in the middle rather at the ends. This is an objective test for degree of type strength.
This heuristic is not arbitrary.
Of course it is.
Now you're just being irrational.
Automatically converting ints to floats is mathematically reasonable, because we consider e.g. 3 and 3.0 to be the same number.
Do we? Given 3/2 and 3.0/2 don't necessarily give the same answer (some languages don't even consider the first operation valid), I'm not sure we do.
Ask a mathematician, and he'll say that they are the same. The underlying concept of number treats 3 and 3.0 as the same thing (until you get to some extremely hairy mathematics, by which time the mathematician you ask will say that the question doesn't even make sense). In mathematics, the difference between 3 and 3+0/10 is, not surprisingly, 0. -- Steven D'Aprano
On 22 Sep 2009, at 22:17 , Steven D'Aprano wrote:
On Wed, 23 Sep 2009 02:35:49 am Masklinn wrote:
On 22 Sep 2009, at 17:46 , Steven D'Aprano wrote:
On Wed, 23 Sep 2009 12:25:32 am Masklinn wrote:
On 22 Sep 2009, at 15:16 , Steven D'Aprano wrote:
On Tue, 22 Sep 2009 01:05:41 pm Mathias Panzenböck wrote:
I don't think this is a valid test to determine how a language is typed. Ok, C++ is more or less weakly typed (for other reasons), but I think you could write something similar in C#, too. And C# is strongly typed.
Weak and strong typing are a matter of degree -- there's no definitive test for "weak" vs "strong" typing, only degrees of weakness. The classic test is whether you can add strings and ints together, but of course that's only one possible test out of many.
And it's a pretty bad one to boot: both Java and C# allow adding strings and ints (whether it's `3 + "5"` or `"5" + 3`) (in fact they allow adding *anything* to a string), but the operation is well defined: convert any non-string involved to a string (via #toString ()/.ToString()) and concatenate.
I don't see why you say it's a bad test. To me, it's a good test, and Java and C# pass it.
Uh no, by your criterion they fail it: both java and C# do add strings and integers without peeping.
What are you talking about? Using Python syntax, we might write:
assert "2"+2 == 4
This test will FAIL for Python, Pascal and other strongly typed languages, and PASS for weakly typed languages. (For some languages, like Pascal, you can't even compile the test!)
Ah I see, we used different meanings for "fail" here. I was thinking of "failing the test" by accepting to run this piece of code (which I find obviously incorrect).
If you're only criterion is that an operation is well-defined, then "weak typing" becomes meaningless...
I don't think I defined any criterion of strong/weak typing.
You conceded that C# adds strings and ints, but disputed that this fact makes C# weakly typed on the basis that (I quote) "the operation is well defined".
I didn't dispute C#'s strong or weak typing (again, I consider this line of inquiry utterly worthless). I merely noted that the operation was clearly defined in the documentation, and am sorry if it came out as anything but a "note of interest".
There's nothing about the definition of weakly typed languages There is not definition of weak typing.
As far as I'm concerned, and as I've already mentioned in this thread, the whole weak/strong axis is meaningless and laughable.
I agree that treating weak/strong as a binary state is an over-simplification, but a weak/strong axis is perfectly reasonable. I really don't think so. Once again, because there is nothing formal about the concept, and everybody just make up their own definition of the axis as they go.
On Wed, 23 Sep 2009 06:55:09 am Masklinn wrote:
There's nothing about the definition of weakly typed languages
There is not definition of weak typing.
The world disagrees with you: http://www.google.co.uk/search?q=define%3A%22weak+typing%22 http://dictionary.reference.com/browse/weak typing http://en.wikipedia.org/wiki/Weak_typing The distinction between weak and strong typing is as useful as that between large and small, and like the later, the lack of a precise distinction doesn't prevent the distinction being useful. (A large virus and a large star are not the same size.) -- Steven D'Aprano
On 24 Sep 2009, at 01:40 , Steven D'Aprano wrote:
The world disagrees with you:
[…] http://en.wikipedia.org/wiki/Weak_typing Not really:
It is the opposite of strong typing, and consequently the term weak typing has as many different meanings as strong typing does
Go to "strong typing" and you have a list of 9 different (and not necessarily compatible) definitions of "strong typing".
On Thu, 24 Sep 2009 07:04:46 pm Masklinn wrote:
On 24 Sep 2009, at 01:40 , Steven D'Aprano wrote:
The world disagrees with you:
Not really:
It is the opposite of strong typing, and consequently the term weak
typing has as many different meanings as strong typing does
Go to "strong typing" and you have a list of 9 different (and not necessarily compatible) definitions of "strong typing".
How does Wikipedia stating that there are many definitions of weak typing support your assertion that "there is not [sic] definition of weak typing"? I think it is disingenuous of you to delete the text of yours I quoted. The terms weak and strong typing are very common use in the real world. If they don't have a single, formal, precise definition, that's too bad, but it doesn't prevent them from being useful so long as we remember that they are fuzzy terms. The English language is full of words and terms with multiple definitions and fuzzy gradings. We manage to communicate about relative differences in size quite well without a single objective and precise definition of "large", and we can communicate about relative differences in strength of the type system of languages quite well without a single objective and precise definition of type strength. -- Steven D'Aprano
I think that the idea that there is a continuum from weak typing to strong typing is useful. At the weak end, the compiler lets you do anything with anything without any declarations. At the strong end, you have to declare everything and explicitly code all type conversions. In practice I suppose, no compiler is completely weak or completely strong in this regard. It's probably possible to devise some sort of metric to be able to place a given language on the weak-strong scale. That's not to say that one language is better than another for being stronger or worse for being weaker. They're just different approaches and philosophies and target different sorts of problems. Where would Python fall? Probably towards the weak end. Is that bad? No way! On Thu, Sep 24, 2009 at 6:54 PM, Steven D'Aprano <steve@pearwood.info> wrote:
On Thu, 24 Sep 2009 07:04:46 pm Masklinn wrote:
On 24 Sep 2009, at 01:40 , Steven D'Aprano wrote:
The world disagrees with you:
Not really: > It is the opposite of strong typing, and consequently the term > weak
typing has as many different meanings as strong typing does
Go to "strong typing" and you have a list of 9 different (and not necessarily compatible) definitions of "strong typing".
How does Wikipedia stating that there are many definitions of weak typing support your assertion that "there is not [sic] definition of weak typing"? I think it is disingenuous of you to delete the text of yours I quoted.
The terms weak and strong typing are very common use in the real world. If they don't have a single, formal, precise definition, that's too bad, but it doesn't prevent them from being useful so long as we remember that they are fuzzy terms. The English language is full of words and terms with multiple definitions and fuzzy gradings. We manage to communicate about relative differences in size quite well without a single objective and precise definition of "large", and we can communicate about relative differences in strength of the type system of languages quite well without a single objective and precise definition of type strength.
-- Steven D'Aprano _______________________________________________ Python-ideas mailing list Python-ideas@python.org http://mail.python.org/mailman/listinfo/python-ideas
-- Gerald Britton
On Thu, 24 Sep 2009 20:06:22 -0400 Gerald Britton <gerald.britton@gmail.com> wrote:
I think that the idea that there is a continuum from weak typing to strong typing is useful.
I think it's fundamentally broken, at least as badly as the notion of a political spectrum from liberal to conservative. The problem with both of those is that there's more than one axis involved. Just as people can have a liberal position on one issue while having a conservative position on another, languages can have some features that give them "weak typing" and others that give them "strong typing". This is different from the "large" vs. "small" distinction previously mentioned, because size can be measured on a single axis, with the large/small distinction depending on the context.
At the weak end, the compiler lets you do anything with anything without any declarations. At the strong end, you have to declare everything and explicitly code all type conversions.
See, you've just pointed out two axis: If declarations are optional because the language does type inferencing, but the language does *no* implicit conversion (ala at least some ML variants), is the typing strong or weak? Likewise, if I have to declare everything, but the language pretty much lets me do anything with anything and will "fix" it (I think it was Waterloo's PL/I that did this....), which end is it at? What about if I have to declare everything, but not provide type information, and you can do anything to anything (BCPL)? By invoking the compiler, you actually referenced yet another type of typing: checking done by the compiler is conventionally known as "static" typing; checking done at run time is "dynamic" typing. This one, at least, has a clearcut definition. But it's not really related to strong .vs. weak. Finally, Python is usually considered strongly - but dynamically - because it doesn't do many implicit conversions. Perl is also dynamically typed, but normally usually considered weekly typed, because it does *lots* of implicit conversion. But - Python will implicitly convert *anything* to a bool. Perl won't do that. Now, which one is strongly typed again? Axis so far: declarations: yes/no/optional. Variables have types: (yes/no/optional). Implicit conversion: yes/no, with a different answer possible for every operand and tuple of operators types in the language.
It's probably possible to devise some sort of metric to be able to place a given language on the weak-strong scale.
I don't think it's possible, because your scale is really a space.
Where would Python fall? Probably towards the weak end. Is that bad? No way!
Like I said, it's usually considered to be near the strong end, because it does few implicit conversion. When compared to other dynamically typed languages, it's *definitely* towards the strong end. But dynamic typing by it's very nature includes things that make typing look weak (types are tied to objects, not variables; no declarations), so people may be tempted to tag it as weakly typed because of those. <mike -- Mike Meyer <mwm@mired.org> http://www.mired.org/consulting.html Independent Network/Unix/Perforce consultant, email for more information. O< ascii ribbon campaign - stop html mail - www.asciiribbon.org
On 09/25/2009 02:52 AM, Mike Meyer wrote:
On Thu, 24 Sep 2009 20:06:22 -0400 Gerald Britton <gerald.britton@gmail.com> wrote:
I think that the idea that there is a continuum from weak typing to strong typing is useful.
I think it's fundamentally broken, at least as badly as the notion of a political spectrum from liberal to conservative. The problem with both of those is that there's more than one axis involved.
Yes, we learned at the university: strong <-> weak static <-> dynamic complete <-> with holes However, these axis aren't completely independent. At one slide our professor showed us a complex diagram of this not really 3D space that included merks for some languages as examples. -panzi
On 09/25/2009 05:57 AM, Stephen J. Turnbull wrote:
Mathias Panzenböck writes:
However, these axis aren't completely independent. At one slide our professor showed us a complex diagram of this not really 3D space that included merks for some languages as examples.
Any chance you could find a link to that diagram?
I searched all the (pdf) slides and didn't find it. I found one diagram but that isn't the one I meant. Thinking of it, I might be the case that the Prof. has drawn it to the blackboard (because he forgot to include it in his slides). I'd have to look through all my notes drawn/written onto the slide printouts of several lectures to find it. I'm not sure if he showed us this diagram in "Type Systems", "Programming Languages" or "Advanced Object Orientated Programming". -panzi
On 25 Sep 2009, at 18:22 , Mathias Panzenböck wrote:
On 09/25/2009 05:57 AM, Stephen J. Turnbull wrote:
Mathias Panzenböck writes:
However, these axis aren't completely independent. At one slide our professor showed us a complex diagram of this not really 3D space that included merks for some languages as examples.
Any chance you could find a link to that diagram?
I searched all the (pdf) slides and didn't find it. I found one diagram but that isn't the one I meant. Thinking of it, I might be the case that the Prof. has drawn it to the blackboard (because he forgot to include it in his slides). I'd have to look through all my notes drawn/written onto the slide printouts of several lectures to find it. I'm not sure if he showed us this diagram in "Type Systems", "Programming Languages" or "Advanced Object Orientated Programming".
-panzi
One of the diagrams on C2's Typing Quadrant page (http://c2.com/cgi/wiki?TypingQuadrant ) might correspond (about halfway down the page, after the comment "Perhaps we need a cube rather than a square")
On 09/25/2009 06:44 PM, Masklinn wrote:
One of the diagrams on C2's Typing Quadrant page (http://c2.com/cgi/wiki?TypingQuadrant) might correspond (about halfway down the page, after the comment "Perhaps we need a cube rather than a square")
Well, they all miss the complete <-> with holes axis. Because languages like C/C++ have something like a reinterpret cast or no bound checks on arrays they have holes. That might not be that of an important axis, but it was represented in this diagram. Whatever. -panzi
Mike Meyer writes:
On Thu, 24 Sep 2009 20:06:22 -0400 Gerald Britton <gerald.britton@gmail.com> wrote:
I think that the idea that there is a continuum from weak typing to strong typing is useful.
I think it's fundamentally broken, at least as badly as the notion of a political spectrum from liberal to conservative. The problem with both of those is that there's more than one axis involved.
The notion that you can't order multidimensional sets (where each dimension is ordered) is simply wrong. You do it every day when you decide to have "a Big Mac with coffee" instead of "a QuarterPounder with a vanilla shake". It is always possible to approximately reduce a multidimensional set to a one-dimensional "spectrum" by use of a mechanical procedure called principal components analysis (the "direction" of the spectrum is the principal eigenvector, in fact). This procedure provides measures of the quality of the approximation as well (eg, the ratio of the principal eigenvalue to the second eigenvalue). The question here then is simply "what is the quality of the approximation, and are there structural shifts to account for?"
Just as people can have a liberal position on one issue while having a conservative position on another, languages can have some features that give them "weak typing" and others that give them "strong typing".
They can take such positions, but historically the correlations were generally high. What has happened in politics in many countries is that there has been a structural realignment such that the component axis traditionally labeled "liberal to conservative" is no longer so much stronger than other components of variation. That doesn't mean that the traditional axis was never useful, nor that a new principal axis hasn't been established (although I don't think it has been established yet in American politics).
Axis so far: declarations: yes/no/optional. Variables have types: (yes/no/optional). Implicit conversion: yes/no, with a different answer possible for every operand and tuple of operators types in the language.
My personal resolution of strong vs. weak typing is that it's useful to help explain which languages I like (strongly typed ones) vs. those I don't. In this, only the implicit conversion axis matters much. Whether variables have types, or declarations are needed, are implementation details related to when type checking takes place (and thus compile-time vs. runtime efficiency), and the tradeoff between translator complexity and burden on the developer to specify things. There are also issues of discoverability and readability which may make it desirable to be somewhat explicit even though a high degree of translator complexity is acceptable to me.
It's probably possible to devise some sort of metric to be able to place a given language on the weak-strong scale.
I don't think it's possible, because your scale is really a space.
It's always possible. Proving that is why Georg Cantor is so famous. The question is whether it's compatible with "what people think", and the answer is "if you must cover all corner cases, no" (ditto, Kenneth Arrow). Can you achieve something usable? I don't know, which is why I'd like to see Mathias's professor's slide!
Where would Python fall? Probably towards the weak end. Is that bad? No way!
Like I said, it's usually considered to be near the strong end, because it does few implicit conversion.
+1 Furthermore, Python's builtin implicit conversions (with the exception of the nearly universal conversion to Boolean, which is a special case anyway) are mostly natural embeddings. Even in cases like "range(10.0)" Python refuses to guess.
On Fri, 25 Sep 2009 13:44:00 +0900 "Stephen J. Turnbull" <stephen@xemacs.org> wrote:
Mike Meyer writes:
On Thu, 24 Sep 2009 20:06:22 -0400 Gerald Britton <gerald.britton@gmail.com> wrote:
I think that the idea that there is a continuum from weak typing to strong typing is useful.
I think it's fundamentally broken, at least as badly as the notion of a political spectrum from liberal to conservative. The problem with both of those is that there's more than one axis involved.
The notion that you can't order multidimensional sets (where each dimension is ordered) is simply wrong. You do it every day when you decide to have "a Big Mac with coffee" instead of "a QuarterPounder with a vanilla shake".
The idea that ordering multidimensional sets matters is simply wrong. Obviously, you can impose an order - and probably many - on any countable set - or any space with a countable number of axis. That leaves three problems, in increasing order of pain: 1) It's not clear the resulting object can be described as a continuum. 2) It's not clear that any of the orders are meaningful. 3) Unless everyone agrees on the order, it's still useless. #3 is the critical one. You've basically moved the problem from selecting one from a set of axis to selecting one from a set of possible orders of a set of axis. Which starts with selecting the set of meaningful axis from the power set - which is noticeably larger than set of axis. The number of meaningful orderings may well approach the power set in size.
The question here then is simply "what is the quality of the approximation, and are there structural shifts to account for?"
*After* you've agreed on which axis matter, and that the PCA is the ordering you want to use.
Just as people can have a liberal position on one issue while having a conservative position on another, languages can have some features that give them "weak typing" and others that give them "strong typing".
They can take such positions, but historically the correlations were generally high. What has happened in politics in many countries is that there has been a structural realignment such that the component axis traditionally labeled "liberal to conservative" is no longer so much stronger than other components of variation. That doesn't mean that the traditional axis was never useful, nor that a new principal axis hasn't been established (although I don't think it has been established yet in American politics).
I've seen people using two political axis for the last couple of decades: financially conservative/liberal and personally conservative/liberal. You can of course collapse that to one axis. You can also describe the solar system with epicycles. But using two axes - or ellipses - is a more powerful model to work with. Which is the point - until we can agree
Axis so far: declarations: yes/no/optional. Variables have types: (yes/no/optional). Implicit conversion: yes/no, with a different answer possible for every operand and tuple of operators types in the language.
My personal resolution of strong vs. weak typing is that it's useful to help explain which languages I like (strongly typed ones) vs. those I don't.
This, of course, tells me pretty nearly *nothing* about which languages you like.
In this, only the implicit conversion axis matters much.
I suspect you care about more than that - or do you weigh Python converting everything to a bool in a boolean context as equivalent to some language that will convert everything to a string if there's a string in the expression? <mike -- Mike Meyer <mwm@mired.org> http://www.mired.org/consulting.html Independent Network/Unix/Perforce consultant, email for more information. O< ascii ribbon campaign - stop html mail - www.asciiribbon.org
Mike Meyer writes:
The idea that ordering multidimensional sets matters is simply wrong.
Urk, I replied to this off-list. Just as well, we're way off-topic, and I can't see how to get back to it from here. Suffice it to say that I stand by what I wrote and I disagree with the above (and most of the following discussion which depends on it). The detailed reply is available to anybody who cares to ask for it. Don't crash my MX, please. :-)
2009/9/25 Gerald Britton <gerald.britton@gmail.com>
I think that the idea that there is a continuum from weak typing to strong typing is useful. At the weak end, the compiler lets you do anything with anything without any declarations. At the strong end, you have to declare everything and explicitly code all type conversions. In practice I suppose, no compiler is completely weak or completely strong in this regard. It's probably possible to devise some sort of metric to be able to place a given language on the weak-strong scale. That's not to say that one language is better than another for being stronger or worse for being weaker. They're just different approaches and philosophies and target different sorts of problems.
The issue of type *declarations* is completely unrelated to strong or weak typing. Haskell is one of the strongest typed languages there is - but the types are usually inferred rather than declared. The compiler has a very strong notion of types internally. Strong and weak typing are to do with the way language treats 'objects' not how they are expressed in code (semantics rather than syntax). Even C# these days has a very limited form of type inferencing. Michael
Where would Python fall? Probably towards the weak end. Is that bad? No way!
On Thu, Sep 24, 2009 at 6:54 PM, Steven D'Aprano <steve@pearwood.info> wrote:
On Thu, 24 Sep 2009 07:04:46 pm Masklinn wrote:
On 24 Sep 2009, at 01:40 , Steven D'Aprano wrote:
The world disagrees with you:
Not really:
It is the opposite of strong typing, and consequently the term weak
typing has as many different meanings as strong typing does
Go to "strong typing" and you have a list of 9 different (and not necessarily compatible) definitions of "strong typing".
How does Wikipedia stating that there are many definitions of weak typing support your assertion that "there is not [sic] definition of weak typing"? I think it is disingenuous of you to delete the text of yours I quoted.
The terms weak and strong typing are very common use in the real world. If they don't have a single, formal, precise definition, that's too bad, but it doesn't prevent them from being useful so long as we remember that they are fuzzy terms. The English language is full of words and terms with multiple definitions and fuzzy gradings. We manage to communicate about relative differences in size quite well without a single objective and precise definition of "large", and we can communicate about relative differences in strength of the type system of languages quite well without a single objective and precise definition of type strength.
-- Steven D'Aprano _______________________________________________ Python-ideas mailing list Python-ideas@python.org http://mail.python.org/mailman/listinfo/python-ideas
-- Gerald Britton _______________________________________________ Python-ideas mailing list Python-ideas@python.org http://mail.python.org/mailman/listinfo/python-ideas
On 25 Sep 2009, at 01:06, Gerald Britton wrote:
I think that the idea that there is a continuum from weak typing to strong typing is useful. At the weak end, the compiler lets you do anything with anything without any declarations. At the strong end, you have to declare everything and explicitly code all type conversions.
IIRC (15+ years...), in some ML variants you need no type declaration but there are no implicit type conversions either. -- Arnaud
Steven D'Aprano writes:
I agree that treating weak/strong as a binary state is an over-simplification, but a weak/strong axis is perfectly reasonable. Count the number of possible mixed-type operations permitted by the language (for simplicity, limit it to built-in or fundamental types). What percentage of them succeed without explicit casts or conversions? If that percentage is 0%, then the language is entirely strong. If it is 100%, then the language is entirely weak. In practice, languages will likely fall somewhere in the middle rather at the ends. This is an objective test for degree of type strength.
Sure, but I think Masklinn's point here is that it's a partial order. I might very well consider a language with a D'Aprano index of 10% more strongly typed than one with an index of 5% (eg, if the 10% are all numeric coercions based on embeddings, while the 5% is various combinations). That said, I think Masklinn is being unreasonable. Although there surely are more folks like him who refuse to accept any notion of "strength of typing", I think most people would be in rough agreement as to which direction the axis points.
Automatically converting ints to floats is mathematically reasonable, because we consider e.g. 3 and 3.0 to be the same number.
I don't think we do consider them to be the *same*; substitutability is one-way. Yes, 3 can be used in place of 3.0 because the integers can be embedded in the reals, but in general not vice versa. We prefer counters (eg in loops) to *not* automatically convert floats to ints. Supplying a float where an int is expected is generally a logic error, not a notational convenience. This notational convenience is very great, however. It's not just a matter of eliding the ".0" from "3.0"; it's also used in contexts like # enumerate the labels on the y-axis y-labels = list(0.50 + 0.05*i for i in range(10)) and in the cake-division problem below. (A hairy mathematician would point out that this can be justified as a notation for repeated addition rather than coercion to float for multiplication, but I'm too bald to bother, besides being an economist anyway.) Note that you cannot write "list(range(0.5,1.0,0.05))" to compute y-labels, though that spelling seems very plausible to me. I would argue that a language that coerces integer to float (or the singleton 'nil' to list, to give another common example) is only slightly more weakly typed than one that doesn't, because of the embedding. But one that coerces float to integer is much more weakly typed than one that doesn't, because there is no embedding.
Do we? Given 3/2 and 3.0/2 don't necessarily give the same answer (some languages don't even consider the first operation valid), I'm not sure we do.
Ask a mathematician, and he'll say that they are the same. The underlying concept of number treats 3 and 3.0 as the same thing (until you get to some extremely hairy mathematics,
No, even naive non-mathematicians may tell you they're different. If you ask any reasonably competent (but non-programmer) sixth grader, they will tell you that 3/2 is "1 with a remainder of 1" (and we have to play scissor-paper-stone to decide who gets the last piece of hard candy), while 3.0/2 is "1.5" (and we split the third piece of cake in half with a fork).
On 23 Sep 2009, at 06:39 , Stephen J. Turnbull wrote:
That said, I think Masklinn is being unreasonable. Although there surely are more folks like him who refuse to accept any notion of "strength of typing", I think most people would be in rough agreement as to which direction the axis points.
I might very well be unreasonable, but I've seen too many discussions of "strong" & "weak" typing degenerate into uselessness (all of them, really) to still consider them worth having, or still consider the concept of weak/strong typing worth talking about until somebody comes up with a precise and formal taxonomy which people will be able to use when discussing the matter. Until then, discussion on the subject will be as enlightening and relevant as discussing which of hydrogen plasma and U-235 tastes the best.
> Ask a mathematician, and he'll say that they are the same. The > underlying concept of number treats 3 and 3.0 as the same thing (until > you get to some extremely hairy mathematics,
No, even naive non-mathematicians may tell you they're different. If you ask any reasonably competent (but non-programmer) sixth grader, they will tell you that 3/2 is "1 with a remainder of 1" (and we have to play scissor-paper-stone to decide who gets the last piece of hard candy), while 3.0/2 is "1.5" (and we split the third piece of cake in half with a fork).
Naive non-mathematicians may indeed tell you that they are different, but they are wrong. Hopefully most readers of this thread, if not professional mathematicians per se, are not naive. I am neither naive nor a mathematician by trade (though I have had healthy doses of maths of all sorts), but if you ask me what three divided by two is, I'll say one-and-a-half, every time, _unless_ you specify that the answer must be an integer, in which case I would answer, "One!" Ironically, since this is a Python list:
3/2 1.5
I have to be explicit to get integer division:
3//2 1
which is precisely my point
On 23 Sep 2009, at 15:25 , Gerald Britton wrote:
Ironically, since this is a Python list:
3/2 1.5
I have to be explicit to get integer division:
3//2 1
which is precisely my point
Unless you're using Python:
3/2 1
You have to be explicit to get true division:
3./2 1.5
wrong! I did use Python: $ python3 Python 3.0.1+ (r301:69556, Apr 15 2009, 15:59:22) [GCC 4.3.3] on linux2 Type "help", "copyright", "credits" or "license" for more information.
3/2 1.5 3//2 1
Surely we're not discussing an idea just for Python 2.x, are we? On Wed, Sep 23, 2009 at 10:16 AM, Masklinn <masklinn@masklinn.net> wrote:
On 23 Sep 2009, at 15:25 , Gerald Britton wrote:
Ironically, since this is a Python list:
3/2
1.5
I have to be explicit to get integer division:
3//2
1
which is precisely my point
Unless you're using Python:
3/2 1
You have to be explicit to get true division:
3./2 1.5
_______________________________________________ Python-ideas mailing list Python-ideas@python.org http://mail.python.org/mailman/listinfo/python-ideas
-- Gerald Britton
Your point is off-point, to say the least. Python Ideas is used to discuss possible new features to the language. Few of these ideas ever go beyond the discussion (this one certainly won't) and fewer still are back-ported to 2.x As to discussing an issue where there is a difference in behavior between Python 2.x and 3.x, it matters -- a lot. On Wed, Sep 23, 2009 at 10:23 AM, Masklinn <masklinn@masklinn.net> wrote:
On 23 Sep 2009, at 16:21 , Gerald Britton wrote:
wrong! I did use Python:
I know. So did I. That was my point.
Surely we're not discussing an idea just for Python 2.x, are we?
I fail to see how this matters. _______________________________________________ Python-ideas mailing list Python-ideas@python.org http://mail.python.org/mailman/listinfo/python-ideas
-- Gerald Britton
Your point is off-point, to say the least. Python Ideas is used to discuss possible new features to the language. My point might be off-topic or off-list, but I don't think the current discussions of the identity between 3 and 3.0 and whether or not strong typing exists (and what it is) have much to do with "new features of the language". They've branched off and are discussions of
On 23 Sep 2009, at 16:32 , Gerald Britton wrote: their own and for discussion's sake. I therefore don't think my point is off-point. The current lines of discussion are not about Python features.
On Wed, Sep 23, 2009 at 10:51 AM, Masklinn <masklinn@masklinn.net> wrote:
On 23 Sep 2009, at 16:32 , Gerald Britton wrote:
Your point is off-point, to say the least. Python Ideas is used to discuss possible new features to the language.
My point might be off-topic or off-list, but I don't think the current discussions of the identity between 3 and 3.0 and whether or not strong typing exists (and what it is) have much to do with "new features of the language". They've branched off and are discussions of their own and for discussion's sake.
I therefore don't think my point is off-point. The current lines of discussion are not about Python features.
Well then, I think your discussion group has just shrunk to a memberhip of one.
_______________________________________________ Python-ideas mailing list Python-ideas@python.org http://mail.python.org/mailman/listinfo/python-ideas
-- Gerald Britton
On Thu, 24 Sep 2009 12:21:07 am Gerald Britton wrote:
wrong! I did use Python:
$ python3 Python 3.0.1+ (r301:69556, Apr 15 2009, 15:59:22) [GCC 4.3.3] on linux2 Type "help", "copyright", "credits" or "license" for more information.
3/2
1.5
3//2
1
Surely we're not discussing an idea just for Python 2.x, are we?
Furthermore, classic division in Python 1.x and 2.x is harmful. Guido has publicly stated that defaulting to integer division in Python 1.x and 2.x was a mistake. In PEP 238 he calls it "a design bug". http://www.python.org/dev/peps/pep-0238/ If anyone doubts that "ordinary people" treat 3 and 3.0 the same, or that 3/2 is 1.5 rather than 1 + 1 remainder, I recommend you do a mini-survey of your family, friends and workmates. Obviously if you ask small children before they have learned about fractions, or mathematicians who have immersed themselves entirely into some field of study using only integers, you may get different results, but 6000-odd years of common practice is to treat "whole numbers" as identical to "decimal numbers where the fraction part is zero"[1]. The *lack* of distinction is so strong that we don't have a simple term to distinguish 3 from 3.0 -- both are "whole numbers". [1] I'm aware that decimal notation doesn't go back 6000 years. But the ancient Greeks and Egyptians were perfectly capable of dealing with fractions, and they too failed to distinguish between a whole number plus a fractional part of zero and a whole number on its own. -- Steven D'Aprano
2009/9/22 Masklinn <masklinn@masklinn.net>
On 22 Sep 2009, at 17:46 , Steven D'Aprano wrote:
On Wed, 23 Sep 2009 12:25:32 am Masklinn wrote:
On 22 Sep 2009, at 15:16 , Steven D'Aprano wrote:
On Tue, 22 Sep 2009 01:05:41 pm Mathias Panzenböck wrote:
I don't think this is a valid test to determine how a language is typed. Ok, C++ is more or less weakly typed (for other reasons), but I think you could write something similar in C#, too. And C# is strongly typed.
Weak and strong typing are a matter of degree -- there's no definitive test for "weak" vs "strong" typing, only degrees of weakness. The classic test is whether you can add strings and ints together, but of course that's only one possible test out of many.
And it's a pretty bad one to boot: both Java and C# allow adding strings and ints (whether it's `3 + "5"` or `"5" + 3`) (in fact they allow adding *anything* to a string), but the operation is well defined: convert any non-string involved to a string (via #toString ()/.ToString()) and concatenate.
I don't see why you say it's a bad test. To me, it's a good test, and Java and C# pass it.
Uh no, by your criterion they fail it: both java and C# do add strings and integers without peeping.
C# will not allow you to add strings to numbers, this is nonsense. If you call ToString() then this is an explicit operation to produce a string representation - and it is this string that you add. It is *not* at all the same as adding arbitrary objects on strings. You can't compile a C# program that attempts to add strings and numbers. I'm also pretty sure you can't override the default behavior on integers etc (C# does have operator overloading but doesn't allow you to redefine operators on the fundamental types - Java doesn't even have operator overloading). Michael
If you're only criterion is that an operation is well-defined,
then "weak typing" becomes meaningless: I could define addition of dicts and strings to be the sum of the length of the dict with the number of hyphens in the string, and declare that
{'foo':'a', 'bar':'b'} + "12-34-56-78-90"
returns 6, and by your criterion my language would be strongly typed. I think that makes a mockery of the whole concept.
I don't think I defined any criterion of strong/weak typing. As far as I'm concerned, and as I've already mentioned in this thread, the whole weak/strong axis is meaningless and laughable.
This heuristic is not arbitrary.
Of course it is.
Automatically converting ints to floats
is mathematically reasonable, because we consider e.g. 3 and 3.0 to be the same number.
Do we? Given 3/2 and 3.0/2 don't necessarily give the same answer (some languages don't even consider the first operation valid), I'm not sure we do.
Perl is weakly typed but it's very hard to cause it to crash,
See the link I previously gave, you might consider Perl weakly typed, not everybody does.
while C++ is strongly typed but easy to cause it to core-dump.
See my response to your previous declaration.
_______________________________________________ Python-ideas mailing list Python-ideas@python.org http://mail.python.org/mailman/listinfo/python-ideas
On 22 Sep 2009, at 22:37 , Michael Foord wrote:
C# will not allow you to add strings to numbers, this is nonsense.
I fear you're wrong. In C#, the operation `"foo " + 3` is perfectly legal and returns `"foo 3"` (and the integer can, of course, be the left hand of the operator). No need for a ToString, that's implicit. In fact, this is quite clearly specified in the C# language specification §7.4.4. "The addition operator" (http://msdn.microsoft.com/en-us/library/aa691375.aspx):
The binary + operator performs string concatenation when one or both operands are of type string. If an operand of string concatenation is null, an empty string is substituted. Otherwise, any non-string argument is converted to its string representation by invoking the virtual ToString method inherited from type object. If ToString returns null, an empty string is substituted.
using System; class Test { static void Main() { string s = null; Console.WriteLine("s = >" + s + "<"); // displays s = >< int i = 1; Console.WriteLine("i = " + i); // displays i = 1 float f = 1.2300E+15F; Console.WriteLine("f = " + f); // displays f = 1.23+E15 decimal d = 2.900m; Console.WriteLine("d = " + d); // displays d = 2.900 } } If you call ToString() then this is an explicit operation to produce a string representation - and it is this string that you add. It is *not* at all the same as adding arbitrary objects on strings. You can't compile a C# program that attempts to add strings and numbers. You might have wanted to test out this theory.
I'm also pretty sure you can't override the default behavior on integers etc (C# does have operator overloading but doesn't allow you to redefine operators on the fundamental types - Java doesn't even have operator overloading). Java somewhat does, since "+" is overloaded on String. What Java doesn't provide is user-defined operator overloading.
2009/9/22 Masklinn <masklinn@masklinn.net>
On 22 Sep 2009, at 22:37 , Michael Foord wrote:
C# will not allow you to add strings to numbers, this is nonsense.
I fear you're wrong. In C#, the operation `"foo " + 3` is perfectly legal and returns `"foo 3"` (and the integer can, of course, be the left hand of the operator). No need for a ToString, that's implicit.
Heh, you're right. How very odd. Michael
In fact, this is quite clearly specified in the C# language specification §7.4.4. "The addition operator" (http://msdn.microsoft.com/en-us/library/aa691375.aspx):
The binary + operator performs string concatenation when one or both operands are of type string. If an operand of string concatenation is null, an empty string is substituted. Otherwise, any non-string argument is converted to its string representation by invoking the virtual ToString method inherited from type object. If ToString returns null, an empty string is substituted.
using System; class Test { static void Main() { string s = null; Console.WriteLine("s = >" + s + "<"); // displays s = >< int i = 1; Console.WriteLine("i = " + i); // displays i = 1 float f = 1.2300E+15F; Console.WriteLine("f = " + f); // displays f = 1.23+E15 decimal d = 2.900m; Console.WriteLine("d = " + d); // displays d = 2.900 } }
If you call ToString() then this is an explicit operation to produce a string representation - and it is this string that you add. It is *not* at all the same as adding arbitrary objects on strings. You can't compile a C# program that attempts to add strings and numbers.
You might have wanted to test out this theory.
I'm also pretty sure you can't override the default behavior on integers
etc (C# does have operator overloading but doesn't allow you to redefine operators on the fundamental types - Java doesn't even have operator overloading).
Java somewhat does, since "+" is overloaded on String. What Java doesn't provide is user-defined operator overloading.
_______________________________________________ Python-ideas mailing list Python-ideas@python.org http://mail.python.org/mailman/listinfo/python-ideas
Weak and strong typing are a matter of degree -- there's no definitive test for "weak" vs "strong" typing, only degrees of weakness. The
Indeed, there certainly different places where language can enforce types. One of them is operators, but I want to point out other places as well. Some languages require explicit type in collections. I believe Pascal and to some extent C#, while certainly not current Python, fall it the category of languages which require containers to declare explicit type of elements. This case is especially relevant to Python, since BFDL considered adding parametrized types (http://www.artima.com/weblogs/viewpost.jsp?thread=86641) though later dropped this idea (http://www.artima.com/weblogs/viewpost.jsp?thread=86641); others, e.g. the original poster, often suggest something similar. I personally continue to be on the side of "strong testing" rather than "strong typing" -- Bruce Eckel said it better than I could do at http://mindview.net/WebLog/log-0025. ilya n.
participants (22)
-
Andrey Fedorov
-
Arnaud Delobelle
-
Bruce Leban
-
Dj Gilcrease
-
Gerald Britton
-
Greg Ewing
-
ilya
-
Imri Goldberg
-
Lie Ryan
-
Masklinn
-
Mathias Panzenböck
-
Michael
-
Michael Foord
-
Mike Meyer
-
MRAB
-
Nick Coghlan
-
Stephen J. Turnbull
-
Steven D'Aprano
-
Talin
-
Terry Reedy
-
VanL
-
Yuvgoog Greenle