From: Quinn Dunkan Date: 2000-02-20T11:49:01-08:00 Subject: [ruby-talk:01528] ruby <=> python Hello! I'm new to ruby-talk, and mostly new to ruby. I'm making a document of some differences between python and ruby, to help reduce the confusion of other newcomers from python. But to do that, I need some help reducing my *own* confusion :) I don't mean to stir up any flames, and if I get responses to some of these, I'll put them in a python_to_ruby faq so there will be recorded documentation for why ruby is the way it is. Even if it sounds like it sometimes, I'm *not* saying "ruby should be different, so it's more familiar to me". More like, "Ruby does this. What's the rationale?" Especially since ruby was created to fill a similar niche as python et al. so every difference must have a reason. Also, note that I *like* ruby. I'm having a good time writing ruby. And I decided not to post to comp.lang.misc, on the assumption that I would get a more insightful discussion on the list (although I am an English-speaking ruby user, and would use comp.lang.ruby if it existed). Also, the list is a more private place and I thought it more polite to get the input of the ruby community first. Also, wading through a high-volume mailing list over a 28.8 modem is a Big Bundle of No Fun. --- Ruby has many types of bindings, with different scopes: @instance_variable $globals local_variable Constant Python has one type of binding. --- Some ruby bindings (@instance_variables, $globals) spring perlishly into existence when looked at, with the value nil. The others raise NameErrors. Python always raises a NameError. Nothing springs anywhere. --- In ruby, there are two ways to access attributes of an object. '.' is used to access methods of an instance. '::' is used to access constants of a class *and* methods of an instance. Unlike python, you can only see methods from instances, and constants from the class: class B C = 'blah' def m 'hello' end end b = B.new b.C -> NameError B.C -> NameError B::C -> "blah" b.m -> "hello" b::m -> "hello" I'm not clear on why this is the case (I mean sorta-similar two access operators. I understand the reasoning behind data hiding :). In python, there is one way to access attributes of an object, which are always visible in both class and instance. So, here are some comparisions between attribute access in ruby and python: ruby python method (in class def) meth object.meth # obj is self attribute (in class def) @attr object.attr # obj is self method (everywhere else) object.meth object.meth Constant Class::Const object.Const in general depends object.attr --- There are two ways to slice lists in ruby. '..' seems to be the familiar python way, and ',' seems to indicate first index and *number of indexes afterward*, which is a strange concept to me. There is one way to slice lists in python. --- Characters are integers in ruby. 'hello'[0] -> 104 There are no characters in python. Just strings of length one. 'hello'[0] -> 'h' I prefer python's way. I don't expect to see a character's underlying ascii representation, except in C, cuz it's weakly typed. And I think "strings are arrays of characters (which are 1-length strings)" is more intuitive than "strings are arrays of integers which are the ascii representation of characters and are displayed as characters when in a string-array". --- Ruby has perl-esque control-statements-that-also-work-as-modifiers: 'foo' if 1 -> "foo" 'foo' if nil -> nil Python doesn't. --- C has continue and break for loop control. Python does exactly the same as C. Perl calls those next and last. Ruby compromises by using next and break. Umm? --- Ruby has iterators, where objects can define their own control structures, which are sort of like methods that take some code as an argument, and can invoke that code via the yield statement. Since sequence objects provide iterators, for and while loops are unnecessary: lst.each { |i| print i } is the same as for i in lst print i end but ruby has both syntaxes, presumably because many people are going to find the for idiom more familiar. I personally find it more difficult to learn, use, and read *two* idioms, one familiar and one less familiar, than just *one* idiom which may be unfamiliar. And if two are there, people will use both. I think this is a point of divergence for me from the perl crowd. --- Not a problem with the language, and I'm sure this will improve, but: English documentation is minimal, and not very clear, to me at least. The user's guide seems to skip a lot of things (and be unclear about other things). The reference manual is better, but is difficult to learn the language from. I'm sure things are much better on the Japanese side of things. Python has an excellent and complete English documentation. The Japanese story may be different :) --- Suppose you write "defined? foo". defined? has to evaluate its arguments, which makes me think it ought to throw a NameError if foo isn't defined'. I'm confused. In python, there's no way to write the identifier foo without it being evaluated, which is what I expect from a non-strict language. --- Ruby uses begin ... rescue ... ensure ... end for exceptions. It's just word choice, I guess. begin could be anything. rescue sounds exception-like. ensure sounds like an eiffel postcondition. Ruby has 'retry' which can be used in an exception handler to retry the sequence, which is nice (Although it resumes from 'begin', instead of resuming from the statement that raised the exception, so it only really works if you have a short begin clause. And it's a nice way to make an infinite loop.). Ruby also has catch (:foo) { throw :foo, "hello" } -> "hello" I'm not sure what the exact difference is between the two forms, or why there are two in the first place. Ruby also uses 'fail' in addition to 'except'. Why use one over the other? I guess it could be important if you want to preserve the poetic rhythm of your code: 'fail' has one syllable while 'except' has two, with stress on the second. Python has one way to raise an exception, and one way to catch it. --- Ruby uses single character global variables $_, $@, etc. ala shell (or perl) that hold special values magically updated by special methods, and which can be more clearly (I think) obtained explicitly. Some of them ($_, $~) don't even act like globals! Python doesn't. Some things which cannot be obtained otherwise are given descriptive names and put in sys, to avoid namespace clutter. --- Ruby has single-inheritance to reduce complexity, which is a nice idea. But in return we get *four* ways to import modules and/or extend classes: include, extend, load, and require. And I'm not clear as to the exact difference between these. Documentation seems to be sparse here. And some more ways to extend a class: class Daughter < Parent # plain inheritance end class << d # singleton class for d end def d.foo # singleton method for d end Python has two ways to import a module 'import module' and 'from module import ...' which is already perhaps more than enough :) It has one way to extend a class (via inheritance). Also, in python, modules are automatically created for a file, and therefore always have the same name as the filename. In ruby, you have to explicitly create the module, which could be named anything, and I'm still trying to figure out the exact semantics for them (which seem to be sort of mostly class-like). --- Ruby has ||, "or", &&, and "and" operators (eek). And they function slightly differently (faq 4.10). j = nil or 1 -> 1 # strange... j -> nil Python has single "or" and "and" operators. --- Methods are not first class in ruby. This means there is a seperate concept of a binding to a method and a binding to an object. This gives rise to proc {} objects, which are sort of like methods. They can be created in a number of different ways: { code } # which gets confused with the hash constructor, and can only be used # in special places (iterators and methods that expect &blocks) proc { code } Proc.new { code } lambda { code } do code end # only in special places, like { code }, and is *mostly* like # { code } except precedence is slightly different And of course, arguments of "normal" methods and Proc objects are handled differently: def f(foo, bar) foo * bar end f = Proc.new { |foo, bar| foo * bar } And apparently default args and the like don't work for || arg lists. And the scoping rules are different: i = 0 p = proc {|n| i = n} p.call(5) i -> 5 And then we have private, public, module_function, protected, and all sorts of other stuff. Careful perusing of the Class, Module, Object, and Kernel documentation is required. So, despite ruby's description as a 'pure object oriented language', methods are not objects, unlike python, where everything is an object (sorry, couldn't resist :) Python has one way of defining a method. There is one 'kind' of binding. --- Dog = Class.new(super = Animal, bark = Method.new([:times], { (['arf'] * times).join(' ') } ) ) hmmm... smalltalk... maybe not :) --- The fact that methods are not first class in ruby means you have to remember two mutually exclusive different ways to do things, depending on whether the value is a method or not: python ruby binding ruby method create new name for object: new = old new = old alias new old delete binding for object: del obj ? undef meth --- "\n" and '\n' are different strings in ruby, which has a similar quoting concept as the unix shell (and therefore perl). "\n" and '\n' are the same in python. --- irb, the interactive ruby toplevel, still has some problems. It tends to get into a weird state, and some things that are valid ruby will not compile (<<-EOF here documents). % irb irb(main):001:0> m NameError: undefined local variable or method `m' for # (irb):1:in `irb_binding' irb(main):002:0> def m irb(main):003:1> 5 irb(main):004:1> end nil irb(main):005:0> m NameError: undefined local variable or method `m' for # (irb):5:in `irb_binding' irb(main):006:0> ^D % irb rb(main):001:0> def m irb(main):002:1> 5 irb(main):003:1> end nil irb(main):004:0> m 5 irb(main):005:0> Python's toplevel works fine, albeit having a slightly different grammar (need an extra blank line after the last block). --- ruby uses dylan-esque def +(arg) end def -(arg) end to override operators. Python has less pretty-looking __add__ __radd__, etc. methods for that. --- Ruby allows some special characters like ?! only at the end of methods to allow dylan / scheme-like naming conventions: obj.destructive!(foo) obj.predicate?(bar) It doesn't allow real scheme-style-function-names, though. Python allows no special characters in any identifiers. --- Ruby has an implicit self: msgs with no receiver are sent to self. Python has an explicit self. msgs with no receiver are simply functions. --- The only things that are false in ruby are nil, false, NIL, and FALSE: if 0 then 'hello' end -> "hello" nil and false, while mostly similar, have 'different behaviours elsewhere' (faq 7.4), but I'm not sure what that means. Careful with that 0 is true stuff, it's easy to forget that if you're not used to it. I'm also not sure why true, nil, and false have UPPERCASE equivalents. I guess nil and false could be useful for 'three value logic' which sometimes pops up (usually in databases). Python has no special purpose booleans. None, 0, __nonzero__() returns 0, and len returns 0 are false. Everything else is true. None and 0 can be used for three value logic.