Feature #5583

Optionally typing

Added by Yasushi ANDO over 3 years ago. Updated over 2 years ago.

[ruby-core:40806]
Status:Rejected
Priority:Normal
Assignee:Yukihiro Matsumoto

Description

Although I know all of you dislike static typing it cannot be denied that there are some people aspire for introducing it in ruby. The dartlang solved the problem in unique way called Optionally Typing. In Dart you can declare types for variables but they are ignored by the compiler with default options.

It looks superb idea for me so that I introduced the optionally typing to ruby as a trial. You can write types for variables if you want then the ruby completely ignores these dirts.

Sample code:

def method(arg)
  arg   
end 

def typed_method(arg) : String
  arg   
end 

def fully_typed_method(arg : String) : String
  arg   
end 

var = 'var'
puts var 

var_with_type : String = 'var_with_type'
puts var_with_type

var_from_method : String = typed_method('var_from_method')
puts var_from_method

@ivar : String = fully_typed_method('@ivar')
puts @ivar

Results:

$ ./truby -Ilib -I. truby_test.rb 
var 
var_with_type
var_from_method
@ivar

I attached my poor patch. Thanks for your consideration.

optionally-typing.patch Magnifier (3.84 KB) Yasushi ANDO, 11/07/2011 12:49 PM


Related issues

Related to Ruby trunk - Feature #6711: Optional typing and method overloading Rejected 07/09/2012

History

#1 Updated by Etienne Vallette d'Osia over 3 years ago

+1

TL;DR

I love the idea!

I don't know if optional typing is the solution, but the more I use Ruby,
the more I miss the robustness that could provide powerful static analysis tools.

Moreover, I often read Ruby code, and it is always clearer when types are provided in doc.
Why writing types in comments should be better than writing them directly in code?

Of course, to be accurate, the typing system should deals with generics (ouch), lambda,
non-yet-defined-classes, respond_to types (but these ones could be seen like implicit module!
Simpler? Oh wait…)

I don't really want to see my favorite language became a Java-like one,
but I'm sure it's possible to handle these cases without adding too much complexity,
at least with adding complexity on the sides, leaving simple code simple :-)

#2 Updated by Alexey Muranov over 3 years ago

TypeError exists in Ruby ([1,2]["a"]), why not to have optional static typing to avoid it when possible. I do not think it can hurt.

#3 Updated by Yasushi ANDO over 3 years ago

  • Status changed from Open to Rejected

No one comments on this issue for a week so that this is rejected. I'm sorry for proposing a dull issue and I'll be back with more fascinating proposal someday.

#4 Updated by Thomas Sawyer over 3 years ago

I don't think it's dull. Actually I think it is obvious future direction. Type information can be very useful for mission critical systems as well as optimization for compilers. While it is not something I'd likely ever use, I've heard other wish they could.

I agree types should be ignored by default, but a "strict" run mode could use/enforce them.

#5 Updated by Kenta Murata over 3 years ago

I like this idea, and I cannot think this is a joke.
I believe Ruby should have optional typing system in the future.
Please reopen this issue and continue discussion.

#6 Updated by Shota Fukumori over 3 years ago

  • Category deleted (Joke)
  • Status changed from Rejected to Open

Let's continue this discussion as not a joke.

#7 Updated by Yukihiro Matsumoto over 3 years ago

Hi,

In message "Re: [ruby-trunk - Feature #5583] Optionally typing"
on Mon, 14 Nov 2011 14:23:14 +0900, Kenta Murata muraken@gmail.com writes:

|I like this idea, and I cannot think this is a joke.
|I believe Ruby should have optional typing system in the future.
|Please reopen this issue and continue discussion.

(a) this syntax conflicts with (already decided) keyword arguments.
(b) in dynamic language like Ruby, optional typing should honor duck
typing, I don't think previous discussion consider this aspect
deeply enough.

                        matz.

#8 Updated by Thomas Sawyer over 3 years ago

@matz

(a) plenty of other ways to define syntax. maybe best way is to separate it from def since it is optional, e.g.

sig foo(String)

def foo(string)
...
end

(b) not sure how it can honor duck typing. i think the whole idea is to (optionally) roast the duck!

#9 Updated by Alexey Muranov over 3 years ago

Yukihiro Matsumoto wrote:

(b) in dynamic language like Ruby, optional typing should honor duck
typing, I don't think previous discussion consider this aspect
deeply enough.

My understanding of how it can possibly work was the following: when foo method that requires a string argument is called, it first of all calls the argument's to_s method (raises an error if there is no such method). I think this is supposed to help catch bugs early and to make the code better documented.
For typed variables, it seems that their class has to be "frozen", and no singleton methods allowed.

#10 Updated by Shugo Maeda over 3 years ago

Hi,

2011/11/15 Thomas Sawyer transfire@gmail.com:

(a) plenty of other ways to define syntax. maybe best way is to separate it from def since it is optional, e.g.

 sig foo(String)

 def foo(string)
   ...
 end

I prefer method annotations to special syntax.

(b) not sure how it can honor duck typing. i think the whole idea is to (optionally) roast the duck!

FYI, Scala supports statically checked duck typing. See
http://markthomas.info/blog/?pf.

--
Shugo Maeda

#11 Updated by Thomas Sawyer over 3 years ago

oh, i see what you mean. so in pseudo code:

sig foo(:to_s)

def foo(stringy_thing)

to mean argument must respond to #to_s.

#12 Updated by Yukihiro Matsumoto over 3 years ago

Hi,

In message "Re: Re: [ruby-trunk - Feature #5583] Optionally typing"
on Tue, 15 Nov 2011 00:36:34 +0900, Shugo Maeda shugo@ruby-lang.org writes:

|FYI, Scala supports statically checked duck typing. See
|http://markthomas.info/blog/?p=66.

It's not concise at all. The beauty of duck typing lives in
its implicitness (I know it's demerit as well).

                        matz.

#13 Updated by Shugo Maeda over 3 years ago

Hi,

2011/11/15 Yukihiro Matsumoto matz@ruby-lang.org:

|FYI, Scala supports statically checked duck typing.  See
|http://markthomas.info/blog/?pf.

It's not concise at all.  The beauty of duck typing lives in
its implicitness (I know it's demerit as well).

I know that you don't like it, and neither do I. Signatures in GNU
C++ (http://docs.freebsd.org/info/gcc/gcc.info.C++_Signatures.html)
look better, but it's not enough. If both signatures and argument
type inference are available, it would be perfect, but those who like
static typing may disagree.

--
Shugo Maeda

#14 Updated by Alexey Muranov over 3 years ago

Excuse me if this thread is not a good place to post this question, but i will appreciate any clarification or a link to an answer.

What is Duck Typing after all, and how is it supposed to work?

According to Wikipedia:

"duck typing is a style of dynamic typing in which an object's current set of methods and properties determines the valid semantics, rather than its inheritance from a particular class"

But what is the "set of methods"? If it is the set of their names, then what if unrelated methods of different objects happen to have the same name? Is there some written requirement about Ruby that, for example, #to_s method has to always convert an object to String? Also, if duck typing is the only typing allowed, then how would you define what String is?

I have been thinking how to check the type of an object, which can be needed, for example, to implement #deep_value (#5531) or other #deep_ method for a hash, and the only nice way i could think of was to use #is_a? method. This would also work if i would want to group classes in some way by their behavior. For example, there are many classes that implement #[] method (Array, Fixnum, Hash, String), so checking if this instance method exists in a class does not always give adequate information about its behavior. So a natural way to group together classes that use this method to store and index objects, like Array and Hash, would be to create an empty module with a unique name, Type::IndexedObjects for example, mix it into Array and Hash and any other class where #[] method behaves similarly, and to use #is_a?(Type::IndexedObjects) to find out the true behavior of an object. But Wikipedia says explicitly that this will not be a Duck Typing, and that in Ruby there shall be only Duck Typing.

-Alexey Muranov.

#15 Updated by Belhorma Bendebiche over 3 years ago

I don't think that duck typing is an issue with optional static typing.

1) It doesn't happen at runtime
2) It only happens if you pass a flag to the interpreter

1) is obvious, the whole point of static typing is that your program doesn't blow up at runtime, so raising errors based on it is pointless.
And with 2), the worst case scenario is you get a warning if you're looking for one. Either way, duck typing works as usual.

This may sound weird but it works out very well in practice (and I have enough practice with AS3 to be able to tell). Even if you strictly type an API, a user can still pass whatever arguments they fancy if they choose to ignore the types, so it's a win-win.

As for syntax:

def foo(bar -> String, baz -> *) -> String

end

Where * or some other token is used to explicitly state dynamic type. It's the same as not providing a type, but in my experience it helps to document it explicitly.

#16 Updated by Alexey Muranov over 3 years ago

Belhorma Bendebiche wrote:

I don't think that duck typing is an issue with optional static typing.

1) It doesn't happen at runtime

A clash between static and dynamic typing can be observed like this (i think there can be more realistic cases):

def foo(bar -> String) -> String
  ...
end

def random_class
  it_is_raining_now? ? String : Array
end

x = random_class.new
foo(x)

So it seems to me that static typing has to be checked in runtime, and the benefits will be:

  1. better documentation of the code,

  2. errors will be raised earlier (at the moment of calling foo in the above example) or will be raised in cases where they wouldn't be raised at all otherwise, and could lead to subtle errors.

  3. (Update) possibility to have "method overloading" based on argument types.

Maybe i do not use terminology correctly and it should not be called static typing in such case.

I propose instead of passing a flag to the interpreter, to do

require 'types'

in the source, which would mix in some predefined Type:: modules into standard classes, and would add hooks for checking for their presence with #is_a?(Type::...) when a type declaration is present.

-Alexey.


Update Declaring method signature dynamically can work like this, for example:

method_signature :foo, [Type::String, Type::Integer], Type::String

def foo(s, n)
  s * n
end

#17 Updated by Koichi Sasada about 3 years ago

Shugo Maeda wrote:

I prefer method annotations to special syntax.

Me too. Any discussion about it?

#18 Updated by Shugo Maeda about 3 years ago

Hi,

Koichi Sasada wrote:

Shugo Maeda wrote:

I prefer method annotations to special syntax.

Me too. Any discussion about it?

Once Matz rejected a proposal of method annotations because he didn't like that methods had such attributes at runtime. It might be acceptable if method annotations have comment-style syntax and are used only at compilation (or another static analysis) time.

Do you have any idea about method annotations in mind, ko1?
Do we have to file a new ticket for method annotations?

#19 Updated by Yusuke Endoh about 3 years ago

  • Status changed from Open to Assigned
  • Assignee set to Yukihiro Matsumoto

#20 Updated by Yukihiro Matsumoto about 3 years ago

  • Status changed from Assigned to Rejected

Although type notation as a comment a la Dart language is pretty interesting, I have to reject this proposal, since the proposed syntax is conflicting.

Matz.

#21 Updated by Alexey Muranov over 2 years ago

Maybe, as a form of typing, Ruby can somehow implement contracts, like in http://en.wikipedia.org/wiki/Design_by_contract ?
Some "contract description language" would need to be invented, and classes or methods would then have a possibility to declare contracts they fulfill:

method_propery C
this method returns a UTF-8 string
end

class_property D
...
end

class_property E
...
end

class T
satisfy :to_s => C
satisfy D & E

def to_s
...
end
end

Then other methods would be able to ask a class if it fulfills a given contract. This would make more sense than simply asking a class if its instances respond to a method with a given name.

Also this could be useful for automatic testing, automatic documentation, and can reduce the amount of necessary comments.

I do not have any clear idea.

P.S. I think it would be inevitable in addition to objects and classes, to have to define values and primitive types, like string, integer, etc.

Also available in: Atom PDF