Hi,
I'm not sure talking about tools is really useful here. It's fairly
obvious what kind of tooling you can have with type support, and there
are many static languages that have in their arsenal a set of tools for
type-checking. I don't think Ruby needs to go there. Even if it did, the
benefits of tooling are only tangential to the practical benefits of
what the compiler/interpreter can do with annotated type information at
run-time.
Let's look at this in a more immediate context. There are a few
real-world Ruby idioms that work around the lack of type information in
the language. Specifically, I'm thinking of method overloading (or the
lack thereof) and run-time type-checking. These are two issues that, as
far as I know, people spend many a minute hacking poorer solutions to,
because the language is limiting.
1) When it comes to overloading, the current solution is to write some
kind of "case" switch or "is_a?"/"respond_to?" checks on classes/method
names, and then dispatching the correct code. Something like:
def run(server)
case server
when Hash; Server.new(server).start
when Server; server.start
end
end
We've all seen and written these methods before. They're annoying to
write, they're even harder to document. Why couldn't we just do (forgive
me, I'm using a different syntax to that which was proposed in this thread):
def run(opts: Hash)
Server.new(opts).start
end
def run(server: Server)
server.start
end
Before all the duck-typists go nuts, there's no reason why you couldn't
specify a duck-type here.
2) Run-time type-checking would have the same benefits. Right now, there
is a lot of code that will check an argument type and then manually
raise ArgumentError. Why can't we just offload this to the method
dispatcher in the interpreter itself?
def format(argument: #to_name)
puts argument.to_name
end
All of the manual exception raising and checking is now hidden, and the
method looks clean and obvious. Since typing is optional, the
compiler-invoked type-checking would only occur on methods written in
this fashion. Optionally you could have the interpreter disable
type-checking globally on methods, if you wanted performance. In fact,
if a library used this setup, they would effectively have a way to
switch off all type checking for performance. Right now, whenever anyone
manually adds an "raise unless arg.respond_to?" statement in their code,
there is no way to switch it off. I'm unsure how anyone could argue that
this kind of functionality, which is only available by annotating types
for the interpreter, is a bad thing.
Finally, type information is worthwhile if for nothing else than
documentation purposes. The ability to introspect a parameter and get a
type, for instance, could go a long way to building automated run-time
type checking libraries, even if the compiler did not support it
implicitly. For example, given,
def foo(x: Fixnum) ... end
Accessing method(:foo).parameters[:x].type could be used to introspect
expected types. The signature is also self-documenting, and we no longer
need to come up with RDoc or even complicated YARD syntax to document
this code. This, by the way, is where we start getting into tooling. As
I mentioned, these benefits are less immediate, but there are some
useful code analysis tools that can be built around such type
information (doc tools, data flow, type checkers).
- Loren
On 9/28/2010 7:52 AM, Asher wrote:
> Martin,
>
> With respect, I think you're considering this backwards, attempting to adjust Ruby in order to address how you're used to dealing with language.
>
> As I see it, one of the major advantages of Ruby is its flexibility, insofar as it figures out for you many details (such as implicit typing). One of the major disadvantages of Ruby is that it has to figure out all of these details. In other words, attempting to satisfy both the advantages and disadvantages of typing in this way is likely to do little other than amplify the disadvantages of Ruby (primarily the underlying weight of the VM) as well as the disadvantages of typing (having to specify details everywhere, having to update details in multiple places for minor changes, etc.)
>
> So you say "reliable, powerful tools" - why does this correspond to typing in any way?
>
> I think instead we should be asking what "powerful" and "reliable" mean in a programming context where typing is not the primary emphasis. What is a hardened Ruby program? I think this is worth asking, but I don't think it's a question whose answer is barred by way of any relation to typing.
>
> Some languages (PHP?) have dealt with this by using "type hints", but I think this simply encourages the wrong approach, emphasizing explicit typing over patterns that are not type-reliant. For instance (as many web pages/blogs will attest), a common pattern for Ruby-newbies is first Class checking, and second method response checking. While there are (rare) appropriate applications for these tests, most of the time they are misplaced and are symptoms of a view of language that comes from somewhere other than Ruby.
>
> Perhaps we would be better served by talking about what sorts of tools we desire. "Reliable" is obvious enough, but what of "powerful"? How are we to define this aspect of tools, particularly regarding Ruby specifically?
>
> So some questions:
>
> 1. What tools should exist?
>
> 2. Which of these tools don't yet exist or should exist with better implementations?
>
> 3. What is the inherent relation of these tools to typing?
>
> I think that much of what we are dealing with here is what I would call a distinction between meta-programming languages and memory-programming languages. Ruby is not a memory-oriented programming language, but a meta- oriented programming language. The functionality of Ruby has far more to do with contingent context elaborated at a run-point in the program context than it does with the mapping of code structures to computer (memory) structures. In other words, the brilliance of Ruby is that the code is not about how the computer works, but is about how the objects work (which require no inherent relation to the computer itself or to their particular mode of storage in memory). This seems to me to deal first and foremost with "getting away" from types while nevertheless retaining the underlying benefits that types provide (albeit mostly invisibly).
>
> Best,
> Asher
>
>
> On Sep 28, 2010, at 6:53 AM, Martin Pilkington wrote:
>
>> Hi Matz
>>
>> Thanks for the reply. I full agree with you (and Alan Kay) that typing can be a pain, though due to benefits in more accurate and effective tools there are advantages to it. If there was a way to easily and reliably get tools as powerful as languages with static typing without the need for the typing then I'd be all for it as I love using duck typed languages and the freedom they give.
>>
>> I did consider structural typing and it could be a route to go down. Ultimately I'm just wanting a better way for me and others to build reliable, powerful tools for Ruby, regardless of how that is approached. I did hit a snag when considering structural typing though, which may be due to my relative inexperience with structural typing, so you might be able to help with a solution.
>>
>> Obviously structural typing is great at easily working out whether two objects are technically interchangeable, whether or not they conceptually are. However, while you can say that a String object is simply one that has methods +,<<, concat, length, split, sub etc, it's somewhat harder to say what the argument and return types of those methods are (of course that is a somewhat bad example given that the return values/types are given for the very base classes and their methods, but you get the idea). This is ultimately the main reason for me wanting some degree of pre-runtime typing (the return types more than the arguments) and I can't see any way to calculate these types without type inference, which itself I see snags with.
>>
>> I'm just wondering if you have any thoughts about getting this method type information? I could just be overlooking something that a fresh (and far more experienced with Ruby) pair of eyes can see, but I'm just struggling a bit with reliable ways to get the type info needed.
>>
>> Thanks
>>
>> Martin
>>
>>
>> On 27 Sep 2010, at 4:29PM, Yukihiro Matsumoto wrote:
>>
>>> Hi,
>>>
>>> In message "Re: [ruby-core:32585] Proposal for Optional Static Typing for Ruby"
>>> on Mon, 27 Sep 2010 20:58:51 +0900, Martin Pilkington<pilky / mcubedsw.com> writes:
>>>
>>> |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).
>>>
>>> Short response:
>>>
>>> "I'm not against types, but I don't know of any type systems that
>>> aren't a complete pain, so I still like dynamic typing." - Alan Kay
>>>
>>> Static typing surely has its benefit, but on the other hand, Ruby the
>>> language strongly encourages duck typing, so that its type system
>>> should not hinder duck typing. As a result, the type checking should
>>> be based on structural types, not nominal types. I don't think your
>>> proposal cares about duck typing or considered structural type
>>> conformance.
>>>
>>> Although I like your<type> notation, that reminds me the scheme
>>> object system, iff we don't have to write them often. I don't think I
>>> could stand to write<type> everywhere.
>>>
>>> matz.
>>>
>>
>