From: Martin Pilkington Date: 2010-09-27T23:41:21+09:00 Subject: [ruby-core:32587] Re: Proposal for Optional Static Typing for Ruby --Apple-Mail-16-201093960 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset=us-ascii Hi Jim The type checking also can apply to return types, so if it knows that = what is returned from Array.new is an array, then it can tell that x and = y are arrays. As for mixins and singletons, these would require some = smarts on the parts of any tools. These tools would have to know about = various ruby idioms and features, so when it sees "def y.bark" it would = know that y now responds to the bark method. As for mixins, this would = entirely depend upon the source file for the mixin and the class using = the mixin being available so that the bits being added and who is = including it are known. Given that Ruby is interpreted this shouldn't be = too big an issue. The only real issue comes with the classes that are = implemented in straight C in the Ruby core library, but there are = various possible solutions to this. Just to be clear, such tools would be independent of adding the syntax = to ruby and so could be developed on their own timescale and may not = even be included as part of the default ruby package. Thanks Martin On 27 Sep 2010, at 2:46PM, Jim Freeze wrote: > Hi >=20 > This sounds interesting, but appears to only provide 'type' checking = on args. Since Ruby objects can have mixins and singletons, method = checking would not work. Consider the case below, where x and y are = Arrays, can this type checking help me enforce #bark on Array? >=20 > x =3D Array.new > y =3D Array.new > def y.bark > "bark" > end >=20 > p y.bark > p y.class >=20 >=20 > On Mon, Sep 27, 2010 at 6:58 AM, Martin Pilkington = wrote: > Hi, >=20 > I know this is my first post on this list and that I'm relatively new = to the Ruby community, and that this can be a somewhat controversial = topic (as I've found by asking about it on the #ruby-lang channel). >=20 > First off, I want to explain who I am. I've been an Objective-C = developer for the past 6 years on the Mac and iOS and have used various = languages such as PHP, Python, Java etc. In the past year I've been = trying to get into Ruby. After several false starts where I've simply = not had time I've managed to make some pretty good progress. I love = Ruby's functionality and how dynamic it is, as it is very close to how = I've worked the past 6 years with my Objective-C development. As with = any language there are some things that I want to see in other languages = (symbols, mixins, almost any character in method names etc) and some = things I would like to see brought from other languages. >=20 > I give this suggestion, not because I don't want to do things the = "ruby" way, but because I genuinely believe that it can help make ruby = better, by aiding in the development of tools that in turn aid = developers in writing code faster and with fewer mistakes. >=20 >=20 > If any of you have used Objective-C, you will have likely encountered = two things. In terms of objects it is duck typed, yet it also offers = static typing. Now there are many differing opinions on static typing. = Some believe everything should be statically typed and to do otherwise = is to allow for errors in your code. Some believe everything should be = duck typed and that with careful coding and testing you can have lots of = flexibility with few, if any errors. To a very large degree I am in the = latter camp. However, I also see the benefits of static typing and how = it can help developers explicitly state assumptions and as such help = developers test those assumptions. >=20 > For those who haven't used Objective-C, I'll give a quick overview of = how it handles typing. Due to its C heritage it is largely statically, = but weakly typed. If you use any C types then you obviously need to type = them as int, float etc. Objective-C adds a few other types to this, but = the key one is the id type. The id type essentially means "anything that = is an object". The reason this exists is because you can have non-object = types, so there needs to be differentiation. In a sense, in Ruby = everything is of the data type "object", and so there is no need to = explicitly state this. >=20 > But Objective-C also has optional static typing for objects. This is = used by the compiler and other tools to perform checks and warn you if = something may be wrong. It is thrown away afterwards and doesn't exist = in the runtime. Much like Ruby, the only way to find out the type of an = object at runtime is to ask it for its class. If you don't want to use = this you can just write everything as id and treat id almost as a = keyword for declaring a variable, sort of like var in javascript. >=20 > So why should Ruby get this? Well the best way to answer that is to = describe some of things that languages with some degree of static typing = have. The first off is pre-runtime checking of code. Have you misspelt a = method or a variable? Did you call a method on an object but forget to = implement it? These things can be warned of before you run your code, = and they can also be run over your entire code. Related to this is = general static analysis, where while not only checking for syntax = errors, it can also check for common bugs and inform you about code = paths that are never run, either because they aren't needed and you = haven't yet removed them or because you're not doing something = correctly. >=20 > Then you have editing tools such as refactoring and autocomplete. = Refactoring can be much more reliable if it knows what types it is = dealing with. If you wanted to rename a method for example, there may be = similarly named methods on multiple classes which are called throughout = your code, but you only want to rename the calls on instances of your = object. And autocomplete becomes more than filtering a list of method = names that have the same prefix as what you have currently typed, if it = knows the class of the object you're calling the method on then it can = severely narrow that down, and often provide you the correct result = first time, meaning less typing. >=20 >=20 > There were some questions that were asked on #ruby-lang and I thought = I would answer them here as you may also have the same questions: >=20 > 1. What if I don't want typing? > The idea would be that this is completely optional, like much of = Ruby's syntax. In Ruby if you don't want () around your method arguments = you don't need them, if you do you can add them in. In this case, if you = want to write these types you can do, if not then you don't. You can = also use typing up until the point where it gets in the way, at which = point you ignore it. Much like with Objective-C, except the general = object type is implied by default in Ruby. >=20 > 2. Why not just use Diamondback Ruby or Mirah or some other similar = system? > These are interesting projects, but they have downsides. For one, I = want to use Ruby and all of the APIs that come with it. Rather than an = entirely new language and runtime, I'm talking about adding one thing to = the language grammar. I also don't want to add any sort of runtime = checking. Code would run exactly the same, as type information would be = discarded when the code is compiled, but it would allow for useful = information for other tools at development time. Lastly, I'd like to see = it as a full language construct rather than comments. >=20 > 3. Why not use comments? > It could be done via comments, but then a standard comment format has = to be required and it is putting language data into what should be = documentation. By doing this as a language feature it sets a standard = way of writing them and keeps code separate from comments. >=20 > 4. What is the point given that there is no full compilation before = hand? > If all you do is write code and run it, none. While this is often how = people write small scripts, it isn't how people write applications. They = also have test suites that they run against it their application and = text editors and IDEs that they use to code this. The benefit is that = the type information can be used to create tools that run some tests for = you and help you write code. To give an example from elsewhere in life, = when things are constructed in remote places, such as dams or wind = turbines, roads need to be built up to them. They aren't actually part = of the construction, but they're needed to help the tools such as = diggers, cranes and workers get there quickly and safely. >=20 > 5. What help is it if you can choose not to use it when static typing = gets in the way? > Yes, in cases where you don't use the typing then there is limited = help from auto complete or refactoring or static analysis. Autocomplete = would default to offering a basic filtered list, static analysis could = take a guess but may be wrong and refactoring may have to resort to = asking you to confirm. However, you find that the times that static = analysis really gets in the way are relatively few. Just because 5% of = the time something doesn't work doesn't mean that it may not be well = worth it for the 95% of the time it can. >=20 > 6. How would you implement it in the language? > This is the trickiest part: what does the syntax look like. As someone = pointed out in #ruby-lang, C style typing is out as 'String foo =3D = "bar"' is another way of writing 'String(foo =3D "bar")'. I have come up = with an idea for the syntax, which from what I can tell wouldn't clash = with any existing syntax. I demonstrate it below by creating a variable = and defining a method (note that you would only have to type a variable = once): >=20 > my_integer =3D "42".to_i >=20 > def to_i( base =3D 10) > end >=20 > Now the above would be absolutely no different at runtime to the Ruby = today of: >=20 > my_integer =3D "42".to_i >=20 > def to_i(base =3D 10) > end >=20 > If you wanted you could mix and match: >=20 > my_integer =3D "42".to_i >=20 > def to_i( base =3D 10) > end >=20 > And to give an example of where static typing gets in the way, take = returning the first object of an array. The array can hold any objects = so you can't know the type but the first method generally takes an = integer argument, so could be defined as: >=20 > def first( n) > end >=20 > So any tool can check the input is in fact an integer, but there is no = return type given so it assumes it can be any type. Now in cases like = this it can be combined with a variable with a type, so while the tools = can't say what you're assigning is the correct type of object, they can = work on the assumption that it is the type of object you said and so it = can make sure that you aren't doing anything 'wrong' with that object = later on. For example: >=20 > my_array =3D ["foo", "bar", "baz"] #Can check the = assignment of myArray > my_string =3D my_array.first #Can check = that myArray responds to first but not that it returns a string > my_string.map {|item| item.do_something} #As we are assuming = aString is in fact a string, we can tell it may not respond to map = (given the nature of message sending we can't be 100% sure, but in the = vast majority of occasions it will be the case) and warn the user >=20 > Of course, this is just my suggestion for the syntax, there are others = out there who have different ideas for a type syntax for ruby and there = may be others on this list. >=20 >=20 > A final question some of you may be thinking, but which wasn't asked = on #ruby-lang: >=20 > 7. Do you have a vested interest? > Yes. I want to invest time in learning Ruby so that I can write = software with it. I've not got masses of experience with it yet, but I = know already it is as fun to use as my current staple language, = Objective-C. There's also that I want to invest time in becoming part of = a community that to some degree has wildly differing opinions on = software development to what I'm used to, so hopefully some of those = opinions will rub off on me and I can apply what I think makes sense to = coding elsewhere. Finally, if I'm going to invest time in a platform = then I want to be able to invest in great tools, whether that means = buying and/or learning existing ones, or writing new ones myself. It is = this last point which is why I'm writing this email as I believe what = I've proposed could help me or others create these great tools. >=20 >=20 > Hopefully I've at least given you something to think about. If you do = have any questions I'd be happy to answer them. And thanks for spending = your time reading this. >=20 > Martin Pilkington >=20 >=20 >=20 > --=20 > Jim Freeze --Apple-Mail-16-201093960 Content-Transfer-Encoding: quoted-printable Content-Type: text/html; charset=us-ascii

Just to be clear, such tools would be = independent of adding the syntax to ruby and so could be developed on = their own timescale and may not even be included as part of the default = ruby = package.

Thanks

Martin

On 27 Sep 2010, at 2:46PM, Jim Freeze = wrote:

Hi

This sounds interesting, but appears to only = provide 'type' checking on args. Since Ruby objects can have mixins and = singletons, method checking would not work. Consider the case below, = where x and y are Arrays, can this type checking help me enforce #bark = on Array?

x =3D Array.new
y =3D Array.new
def y.bark
  = "bark"
end

p y.bark
p y.class


On Mon, Sep 27, 2010 at 6:58 AM, Martin Pilkington = <pilky@mcubedsw.com> = wrote:
Hi,

I know this is my first post on this list and that I'm relatively new to = the Ruby community, and that this can be a somewhat controversial topic = (as I've found by asking about it on the #ruby-lang channel).

First off, I want to explain who I am. I've been an Objective-C = developer for the past 6 years on the Mac and iOS and have used various = languages such as PHP, Python, Java etc. In the past year I've been = trying to get into Ruby. After several false starts where I've simply = not had time I've managed to make some pretty good progress. I love = Ruby's functionality and how dynamic it is, as it is very close to how = I've worked the past 6 years with my Objective-C development. As with = any language there are some things that I want to see in other languages = (symbols, mixins, almost any character in method names etc) and some = things I would like to see brought from other languages.

I give this suggestion, not because I don't want to do things the "ruby" = way, but because I genuinely believe that it can help make ruby better, = by aiding in the development of tools that in turn aid developers in = writing code faster and with fewer mistakes.


If any of you have used Objective-C, you will have likely encountered = two things. In terms of objects it is duck typed, yet it also offers = static typing. Now there are many differing opinions on static typing. = Some believe everything should be statically typed and to do otherwise = is to allow for errors in your code. Some believe everything should be = duck typed and that with careful coding and testing you can have lots of = flexibility with few, if any errors. To a very large degree I am in the = latter camp. However, I also see the benefits of static typing and how = it can help developers explicitly state assumptions and as such help = developers test those assumptions.

For those who haven't used Objective-C, I'll give a quick overview of = how it handles typing. Due to its C heritage it is largely statically, = but weakly typed. If you use any C types then you obviously need to type = them as int, float etc. Objective-C adds a few other types to this, but = the key one is the id type. The id type essentially means "anything that = is an object". The reason this exists is because you can have non-object = types, so there needs to be differentiation. In a sense, in Ruby = everything is of the data type "object", and so there is no need to = explicitly state this.

But Objective-C also has optional static typing for objects. This is = used by the compiler and other tools to perform checks and warn you if = something may be wrong. It is thrown away afterwards and doesn't exist = in the runtime. Much like Ruby, the only way to find out the type of an = object at runtime is to ask it for its class. If you don't want to use = this you can just write everything as id and treat id almost as a = keyword for declaring a variable, sort of like var in javascript.

So why should Ruby get this? Well the best way to answer that is to = describe some of things that languages with some degree of static typing = have. The first off is pre-runtime checking of code. Have you misspelt a = method or a variable? Did you call a method on an object but forget to = implement it? These things can be warned of before you run your code, = and they can also be run over your entire code. Related to this is = general static analysis, where while not only checking for syntax = errors, it can also check for common bugs and inform you about code = paths that are never run, either because they aren't needed and you = haven't yet removed them or because you're not doing something = correctly.

Then you have editing tools such as refactoring and autocomplete. = Refactoring can be much more reliable if it knows what types it is = dealing with. If you wanted to rename a method for example, there may be = similarly named methods on multiple classes which are called throughout = your code, but you only want to rename the calls on instances of your = object. And autocomplete becomes more than filtering a list of method = names that have the same prefix as what you have currently typed, if it = knows the class of the object you're calling the method on then it can = severely narrow that down, and often provide you the correct result = first time, meaning less typing.


There were some questions that were asked on #ruby-lang and I thought I = would answer them here as you may also have the same questions:

1. What if I don't want typing?
The idea would be that this is completely optional, like much of Ruby's = syntax. In Ruby if you don't want () around your method arguments you = don't need them, if you do you can add them in. In this case, if you = want to write these types you can do, if not then you don't. You can = also use typing up until the point where it gets in the way, at which = point you ignore it. Much like with Objective-C, except the general = object type is implied by default in Ruby.

2. Why not just use Diamondback Ruby or Mirah or some other similar = system?
These are interesting projects, but they have downsides. For one, I want = to use Ruby and all of the APIs that come with it. Rather than an = entirely new language and runtime, I'm talking about adding one thing to = the language grammar. I also don't want to add any sort of runtime = checking. Code would run exactly the same, as type information would be = discarded when the code is compiled, but it would allow for useful = information for other tools at development time. Lastly, I'd like to see = it as a full language construct rather than comments.

3. Why not use comments?
It could be done via comments, but then a standard comment format has to = be required and it is putting language data into what should be = documentation. By doing this as a language feature it sets a standard = way of writing them and keeps code separate from comments.

4. What is the point given that there is no full compilation before = hand?
If all you do is write code and run it, none. While this is often how = people write small scripts, it isn't how people write applications. They = also have test suites that they run against it their application and = text editors and IDEs that they use to code this. The benefit is that = the type information can be used to create tools that run some tests for = you and help you write code. To give an example from elsewhere in life, = when things are constructed in remote places, such as dams or wind = turbines, roads need to be built up to them. They aren't actually part = of the construction, but they're needed to help the tools such as = diggers, cranes and workers get there quickly and safely.

5. What help is it if you can choose not to use it when static typing = gets in the way?
Yes, in cases where you don't use the typing then there is limited help = from auto complete or refactoring or static analysis. Autocomplete would = default to offering a basic filtered list, static analysis could take a = guess but may be wrong and refactoring may have to resort to asking you = to confirm. However, you find that the times that static analysis really = gets in the way are relatively few. Just because 5% of the time = something doesn't work doesn't mean that it may not be well worth it for = the 95% of the time it can.

6. How would you implement it in the language?
This is the trickiest part: what does the syntax look like. As someone = pointed out in #ruby-lang, C style typing is out as 'String foo =3D = "bar"' is another way of writing 'String(foo =3D "bar")'. I have come up = with an idea for the syntax, which from what I can tell wouldn't clash = with any existing syntax. I demonstrate it below by creating a variable = and defining a method (note that you would only have to type a variable = once):

<Integer> my_integer =3D "42".to_i

def <Integer> to_i(<Integer> base =3D 10)
end

Now the above would be absolutely no different at runtime to the Ruby = today of:

my_integer =3D "42".to_i

def to_i(base =3D 10)
end

If you wanted you could mix and match:

my_integer =3D "42".to_i

def <Integer> to_i(<Integer> base =3D 10)
end

And to give an example of where static typing gets in the way, take = returning the first object of an array. The array can hold any objects = so you can't know the type but the first method generally takes an = integer argument, so could be defined as:

def first(<Integer> n)
end

So any tool can check the input is in fact an integer, but there is no = return type given so it assumes it can be any type. Now in cases like = this it can be combined with a variable with a type, so while the tools = can't say what you're assigning is the correct type of object, they can = work on the assumption that it is the type of object you said and so it = can make sure that you aren't doing anything 'wrong' with that object = later on. For example:

<Array> my_array =3D ["foo", "bar", "baz"]       =  #Can check the assignment of myArray
<String> my_string =3D my_array.first         =             #Can check that myArray = responds to first but not that it returns a string
my_string.map {|item| item.do_something}        #As = we are assuming aString is in fact a string, we can tell it may not = respond to map (given the nature of message sending we can't be 100% = sure, but in the vast majority of occasions it will be the case) and = warn the user

Of course, this is just my suggestion for the syntax, there are others = out there who have different ideas for a type syntax for ruby and there = may be others on this list.


A final question some of you may be thinking, but which wasn't asked on = #ruby-lang:

7. Do you have a vested interest?
Yes. I want to invest time in learning Ruby so that I can write software = with it. I've not got masses of experience with it yet, but I know = already it is as fun to use as my current staple language, Objective-C. = There's also that I want to invest time in becoming part of a community = that to some degree has wildly differing opinions on software = development to what I'm used to, so hopefully some of those opinions = will rub off on me and I can apply what I think makes sense to coding = elsewhere. Finally, if I'm going to invest time in a platform then I = want to be able to invest in great tools, whether that means buying = and/or learning existing ones, or writing new ones myself. It is this = last point which is why I'm writing this email as I believe what I've = proposed could help me or others create these great tools.


Hopefully I've at least given you something to think about. If you do = have any questions I'd be happy to answer them. And thanks for spending = your time reading this.

Martin Pilkington



--
Jim = Freeze

= --Apple-Mail-16-201093960--