You wrote: > Hello, Hello too, :-) (...) > First my global impression which survived translation of some of my > scripts is that ruby is a perfect replacement for perl and python > (when translating some scripts I had only some minor annoyances; on > the other hand I could achieve some substantial improvements due to > the higher-level nature of ruby). Some of the minor annoyances were: > > - I had trouble using sort! in method-chaining because > > irb(main):006:0> [1,2].sort! > [1, 2] > irb(main):007:0> [1].sort! > nil > > the reason why sort! does not return its result for arrays of length > 1 eludes me. sort! returns 'nil' if the list was not necessary to be sorted. A list with only one element cannot be sorted sensefully, hence the 'nil'. Perhaps that effect of sort! will be changed in future (if my interpretation of past discussions is right). > - In perl, if one wants to sort according to several criteria, one can > write something like that > > sort { length($a) <=> length($b) or $a cmp $b } In Ruby only 'nil' and 'false' are false. All other are true; so also the value zero! But there is a method Numeric#nonzero? that returns 'nil' if the receiver was zero, otherwise it returns the receiver. You can use it to write the code block of sort like: { (a.length <=> b.length).nonzero? || a <=> b } (...) > - I have some problems with scopes. In particular, that one can > not define local functions. The closest I could come with is to > define a local Proc object and use .call on it. Is that the > recommended way? The trick is here, that you are even not *able* to define a function. *Neither* a global one *nor* a local one. You can only define methods. Remember Ruby is fully OOL. Not a hybrid like Python or C++. A method, however, *ought* to belong to a certain class. If you define a method on toplevel outside of every class definition, that method belongs to class Object and will become a private instance method of it. As such, it is visible on all places in your code as every class/module inherits from class Object at last! So it seems you define a function but in reality you was fooled by Ruby there! ;-) So the closest to come to a local function is indeed a local Proc object. You could use the methods Proc#call or Proc#[] to call such an instance. Proc instances will also often used as anonymous callback 'functions'. I am sure you will like them :-) > The main reason I looked at ruby is that I had very high hopes for > this language: my job is mathematics and I thought ruby might be > well suited for that. Mathematical programming involves defining I am not a mathematican, but I am sure it will fit your needs! But please have also a look to the Ruby Application Archive (RAA) http://www.ruby-lang.org/en/raa.html to find some valuable modules, that may help you here for mathematical tasks. Some among them: - NArray - BigFloat - NumArray - Polynomial (...) > overloading), but other people including matz may have another view > which would interest me. Erhm ... what? Lack of overloading? Impossible ... ah you mean overloading by parameter type, yes? That is indeed not available in Ruby (nor in Python or Smalltalk, BTW). The reason is that variables are not typed in such languages. Therefore it is difficult (perhaps impossible in some cases?) for the compiler to fiddle out on compilation time what kind of method to be called later on! You can think from method invocation as sending a method selector to a certain object. Like that: a = 3 b = 5 a.send(:+, b) # => 8 If dispatching would not be done via selector only but also by argument type, the message lookup would slow down, IMO. First find the *group* of messages that *could* apply, then look whether argument-type-overloading applied or not. If not call the method; if yes look for the one with the right argument signature! And how to handle lookup in parents? Parent contain overloaded methods, child only one method catching all possible types ... pfffhhh! Or if you design a class with overloaded-on-arguments methods, how would you prevent me to overload your methods again but this time catching *all* possible types of arguments? Not possible? But if I need to? I really do not know, if a solution of all this is worth the trouble! Not that I believe that there *is* a senseful undoubtable and backward compatible solution that would not bite us another way around or weaken Ruby's nice dynamic behavior ... But there is the coerce mechanism ... (...) > Now the code above works fine as long as I work only with > Fracs. Suppose now that I want to define the addition of a Frac and > an integer: (...) > thought I would have a look. Well, miracle, > > 2+Complex(1,3) > > works! This apparently uses a mechanism for which I could not find > non-Japanese documention, involving 'coerce'. If I mimic what I > found in 'Complex', that is add: > > def coerce(other) > [Frac.new(other), self] > end That was exactly what I meant with the 'coerce' mechanism. > now my example works. I would like a clear explanation of exactly > what is the mechanism here. It seems to me that the method + for > integers has a pre-defined hook to look for coerce for an unknown > type. It is also probably to provide a similar hook for future I think you have understood the coerce mechanism very well! I would really not know what else to describe to you. > additions that in Complex one has: > > def + (other) > if other.kind_of?(Complex) > re = @real + other.real > im = @image + other.image > Complex(re, im) > elsif Complex.generic?(other) > Complex(@real + other, @image) > else > x , y = other.coerce(self) > x + y > end > end > > but I feel: > -the above code is complicated, and clumsy, compared to > overloading It depends. Above I have tried to show you the problems we would struggle in if we add overloading-on-arguments to such a highly dynamic language like Ruby. I dare to guess that there are cases where a compiler would even not *able* to tell you what kind of object is passed to a method right now during compilation time! So perhaps it is still better to let the method analyze its arguments if necessary instead of teaching the compiler to guess ... > -contrary to overloading, there is no possibility to extend an > already-existing method for an already-existing type if no hook > has been provided. Not totally true! You could alias the old method and create a new one with same name like the old one but different behavior! Like that: class FooNbr attr :n def initialize(n) @n = n end def +(other) self.n + other.n end end # Not very clever the method FooNbr#+? FooNbr.new(12)+2 wouldn't # work as 2+FooNbr.new(12) wouldn't work too. So let us change it! class FooNbr alias :oldplus :+ def +(other) if other.type < FooNbr self.oldplus other else x, y = self.coerce(other) x + y end end def coerce(other) [self.n, other] end end a = FooNbr.new(12) b = FooNbr.new(2) a + b a + 5 7 + b You see: although the original FooNbr#+ had no coerce, we have simply introduced it by 'reopen' the class definition and remembering and overwriting the original FooNbr#+ method with a new one. > This last point bothers me: it is very nice that in ruby one can > dynamically add to a class, by reopening it. Overloading is a way to > 'reopen' a method, and the possibility to reopen a class is not so > useful without it It is not really necessary, IMHO, as I have tried to show you above. > Ok, now what did I miss, and what is the rationale for no overloading, > or the replacement for it that I missed? Let me thank you for your critical questions and remarks. I hope, though, that I was able to give you some pointer/hints why you overloading scheme would be more trouble than blessing in my opinion at least ... (...) Best regards, \cle