On 5/31/05, Caleb Clausen <vikkous / gmail.com> wrote: > Austin Ziegler wrote: >> # :parameter bar: aString >> # :parameter baz: anArray or +nil+ >> # :returns: true if aString ... >> def foo(bar, baz = nil) >> I *WANT* type hints. I have believed that they are useful for >> things like SOAP from the beginning. I don't, however, want >> anything that looks like type declarations in the method >> declaration. >> Thus, if we allow people to do: >> def foo(bar: String, baz: [ NilClass, Array ] = nil) >> : >> end >> They will. And all of the clean, easy-to-read-and-use Ruby code >> that we've come to love will go away. > I don't see how what you propose is all that different, > semantically, from calling out the type in the method header. You > seem to be arguing that: 'I want X like in other languages, but I > don't want it to look like it looks in other languages, because > programmers from other languages can import their bad habits.' Then you're not paying attention. Sorry if that offends you, but you're just not paying attention. Type hints are primarily a documentation feature. Let me repeat that for emphasis: it is a documentation feature. If an optimizing Ruby compiler is able to take advantage of it -- great. If not ... too bad. This is intended as both human and machine documentation for automatic documentation tools (rdoc), IDE autocompletion, and SOAP method descriptions (and the like). > And to add a feature that doesn't at least resemble the syntax for > that feature in most other languages is to compromise the > (currently much battered) principle of least surprise, at least > for those programmers coming to ruby from another language. DO *NOT* USE POLS in your argument. It doesn't apply. Matz has indicated that it's just so much crap. I don't particularly *care* if programmers coming from other languages are confused by a type hinting system that doesn't look remotely like their static typing system -- it isn't the same. It shouldn't be the same. It shouldn't give them a false sense of understanding as to what it is. > The usual syntax where the type is embedded in the variable > definition has some advantages: it's compact, and it keeps related > things together. It's not for no reason that langauge after > language that actually implements this has done it (more-or-less) > the same way. It also carries tons of disadvantages, as I've expounded before, but will happily repeat again for those not paying attention: 1. It looks like the stuff in other languages, but because Ruby isn't statically typed (thank GHU for that), it won't have the same meaning as it does in those languages. 2. If it does have the same meaning in those languages, we're no longer talking about Ruby. 3. It will encourage people to use it for the wrong reasons in the wrong way. 4. It becomes more than informational. All of these are killer problems. Type hinting in Ruby should be informational. No more. >> Especially the -use part, because if I want to use a StringIO >> object now, I'll either need to modify the library, or get the >> String out of the StringIO before I can use it. > Specifying an overly restrictive type is an error. One can write a > bad program in any language, as the various obfuscated programming > contests have shown. Just because this is possible is no reason to > limit what good programs can do. You haven't been paying attention. StringIO doesn't inherit from String or IO, but it will act like either. If I add a #read method and a #write method to a random object, it will act a lot like an IO. If I add #to_str to said object, it acts a lot like a String. Specifying a restrictive (that is, non-informative) type AT ALL prevents me from using many of these features that make the language we're using Ruby. Emphasis: restrictive type indicators will make the language that does this Not Ruby. >> It has been conclusively shown that type restrictions based on class >> names precisely do NOT do that in Ruby. Those restrictions, in fact, >> do NOT make the code more robust, and are therefore bad things. > Type and class are not the same thing. Class is one variety of type, > but there are others. For instance, there is the 'method signature', > (or duck type,) the set of methods that can be called. You try to > rebut this notion: Oh, please *don't* try to lecture me on this stuff, Caleb. You'll just piss me off. The method signature is not related to the "duck type." If you've used Ruby for any length of time, you recognise that as well. I'm not Matz -- or even Dave Thomas -- but duck typing is, ultimately, not *caring* about the type of object you're provided. It's just using the type of object. >> I am absolutely positive that this should not be Ruby 2.0. It >> complicates things unnecessarily. I think that we can agree that >> Java-style Interfaces are poor substitutes for mixins; the >> proposal for interfaces in Ruby are equally poor. > You manage to criticize without letting us know what your actual > objections are. What things are complicated, and how? Java > interfaces are a poor substitute for mixins, but that's because > they're not meant to be mixins. I would say instead: Java > interfaces are a poor substitute for duck types, (since, like > everything else in Java, they require a big pile of declarations > ahead of time) but we can make the Ruby version work the right > way, with a lot less declarations. (Only a little pile.) No, we can't. Interface declarations are simply wasted code time and space. It's that simple. (And Java interfaces *are* a poor substitute for mixins; they are the way that Java implements MI, but they require independent implementation in all cases. Ruby implements MI through mixins, but like C++'s STL, they have a common implementation.) Simple rebut of your attempt at justification: at what point in a class definition can you conclusively say that it is -- or is not -- an Enumerable? Given that classes in Ruby are open, you can't say it until you try to use it like an enumerable. class Foo include Enumerable end a = Foo.new a.inject(0) { |a, b| a + b } # NoMethodError: undefined method `each' for #<Foo:0x2b5f290> class Foo def each yield self end end a.inject(0) { |a, b| a + b } Obviously, this class won't work -- there are other parts missing, but not until I've defined an #each method is Foo an enumerable. What value would be something like a NoEnumerableInterface error be as opposed to the simple "undefined method `each'" that we get? Enumerable's documentation clearly states that it requires the #each method be implemented for the Enumerable methods to work. Why do we need an "interface" for that? The interface -- and implementation -- is in Enumerable. We don't need anything more than that. >> Mmm. I'm not sure that I agree. Part of what I'm thinking here >> has to do with what Microsoft has done with the .NET platform and >> Java has done with Hotspot compiling. > People expect too much from hotspot and the like. It works great > for Java, sure, but that's in large part because Java is > statically typed. Expecting the same performance in a language > with no type information on variables whatsoever is unrealistic. Not at all. Self is an indication that my suggestion will work: [...] the compiled method is specialized on the type of the receiver. If the same message is later sent to a receiver of different type (e.g., a float instead of an integer), a new compilation takes place. This technique is called customization [...] the compiled methods are placed into a cache from which they can be flushed for various reasons; therefore, they might be recompiled from time to time. Furthermore, the current version of the compiler will recompile and reoptimize frequently used code, using information gathered at run-time as to how the code is being used [...] http://rubyurl.com/aFVmq (http://research.sun.com/self/release_4.0/ Self-4.0/manuals/Self-4.1-Pgmers-Ref.pdf) Gee. It looks like I'm right. Self is an untyped language -- and the HotSpot technology in Java is *based on the research for Self*. (Indeed, note the point about the compiled cache and recompile and reoptimize. That describes HotSpot exactly.) > And no, type inferencing _by_itself_ will not solve the problem. > Type inferencing works in ML, but ML, like Java and C# is not a > dynamic language. ML lacks a feature that Ruby has: > method_missing. To understand why this is important, let me > briefly explain type inferencing. IIRC, Haskell also supports type inferencing, and is far more closely considered a dynamic language. Method missing is a simple case of unoptimizable code. At any rate, it's rather moot, since the support (above) for the original point that I made rather shoots down what you've said. [...] > Speed is only one advantage to a static typing system. In general, > static typing makes it easier (for programs as well as people) to > analyse programs that use it. Bullshit. This is a lie told by proponents of statically typed languages that has been shown false again and again and again. Static typing doesn't increase safety, ability to be analysed, or anything else -- that doesn't help the compiler of said statically typed language. There are side benefits from IDEs that have been observed in the last serveral years, but statically typed languages have been around a lot longer than autocompletion. And we *still* get buffer overruns. Sorry, but I question even the belief that speed is an advantage to a static typing system -- remember that C++ was *slower* than C for years (and in some cases, still is), and they're both statically typed languages. (Hint: even statically typed languages need to break the chains more often than proponents want to admit. In Java it's Object. In C/C++ it's void*. Both require a lot of care and work to make them happen.) -austin -- Austin Ziegler * halostatue / gmail.com * Alternate: austin / halostatue.ca