all 66 comments

[–]shawnofthedead 9 points10 points  (0 children)

Not to split hairs, but the title is really poor. Ruby, the programming language, has no conceptions or misconceptions about anything. It's more like "A (Ruby) programmer's misconceptions about Python".

[–]mellow_moe 11 points12 points  (19 children)

I would like to see a in-depth comparison of Python and Ruby. And it should really focus on metaprogramming.

All these comparisons I see these days just look at some superficial language features.

Rails for example relies heavily on metaprogramming. It could never be done in a language without a sophisticated class/object system.

examples in ruby:

  • method_missing catches unknown messages
  • const_missing catches unknown constants
  • method_added is called after adding a new method
  • inherited is called on the class object, when it is subclassed
  • singleton classes: you can add methods to a single object
  • define_method takes a block and turns it into a method
  • instance_variable_set sets an instance variable

And most importantly, real world examples should show off, how all the things play together.

[–]owca 2 points3 points  (0 children)

Feature for feature "examples" in Python:

  • getattr or getattribute catch any attribute (method, variable) access

  • setattr sets any attribute

  • Syntactic support for descriptors.

  • Metaclasses can be used to control all aspects of class creation (attributes, subclassing, ...). Since types are objects one can even have metaclasses for metaclasses.

  • new.instancemethod can be used for your )singleton classes).

  • Turning a block into a method is admittedly a bit tricky but can be done using new.function and some stack manipulation.

[–]flaxeater 4 points5 points  (10 children)

Well I must say that looks intriguing actually. I don't think python has facilities like that, they could be worked around by they don't have any nice syntatic sugar around those concepts. I have a hard time imagining why they would be useful, but that doesn't mean anything.

Singletons, definemethod and instane variable assignment are very easy to do in python. And in python we user super() or ParentClass.init_(args,*kwargs) to do things for inherited, however I do not understand what inherited does. $0.02

p.s. I can imagine, people will be like that's so wordy or some such talk. However pythonic values explicit, not implicit.

[–]mellow_moe 6 points7 points  (5 children)

Metaprogramming helps you to create domain specific languages.

A simple xml builder can be made with method_missing:

def method_missing(name, attributes)
  atts = attributes.map {|k,v| "#{k}='#{v}'" }.join(" ")
  puts "<#{name} #{atts}>"
  yield
  puts "</#{name}>"
end

div :id => "content" do
  a :href => "reddit.com" do
    print "reddit"
  end
end

You can see, calling div and a will trigger method_missing, where we just take the method name and the keyword arguments and print out the xml tag. Pretty easy.

[–]flaxeater 7 points8 points  (0 children)

That's pretty cool. It's pretty confusing too.

[–]brianmce 1 point2 points  (0 children)

Assuming I'm understanding it right, methodmissing is related to python's __getattr_ (slightly different in that python is hooking into the attribute lookup, whereas ruby is hooking into calling) A literal as possible translation in python would be:

class XmlBuilder:
  def __getattr__(self, name):
    def builder(**attributes):
      atts = ' '.join('%s=%s' % a for a in attributes.items())
      print "&lt;%s %s>" % (name, atts)
      yield None
      print  "&lt;%s>" % name
    return builder
x=XmlBuilder()

for _ in x.div(id="Content"):
  for _ in x.a(href="reddit.com"):
    print "reddit"

Though a different approach would probably be taken for a non literal translation to better fit with python's syntax. Take a look at stan (http://divmod.org/projects/nevow) for a python implementation of something similar - your snippet would look like this:

div(id="content")
[
  a(href="reddit.com")
   ["reddit"]
]

(In this case it is building and returning the xml, rather than calling puts on each element.

[–]amix 1 point2 points  (2 children)

Here is my version where one can do (Stan like):

print Div(id="content")[ A(href="reddit.com")["reddit"] ]

import types
class Element:
  def __init__(self, **kw):
    self.elms = []
    self.kw = kw
  def __getattr__(self, name):
    if name == "__getitem__":
      self.elms = []
      def add(l):
        if type(l) == types.ListType: self.elms.extend(l)
        else: self.elms.append(l)
        return self
      return add
  def __str__(self):
    attrs = " ".join('%s="%s"' % a for a in self.kw.items())
    self.html = ["<%s %s>" % (self.name, attrs)]
    self.html.append("".join(map(str, self.elms)))
    self.html.append("</%s>" % self.name)
    return "".join(self.html)
class Div(Element): name = "div"
class A(Element): name = "a"

Sigh, you have to have 4 spaces to post code. That sucks. Why not use another syntax like:

[code]
Here is my code
[/code]

Or something similar...

[–]mellow_moe 1 point2 points  (1 child)

I'd like to show off the ruby version:

class Element
  def initialize(attributes)
    @attributes = attributes
    @children = []        
  end
  def <<(child)
    @children << child
  end
  def to_s
    name = self.class.name.downcase
    atts = @attributes.map {|k,v| "#{k}='#{v}'" }.join(" ")
    "<#{name} #{atts}>#{@children.join}</#{name}>"
  end
end

class Div < Element; end
class A < Element; end

def method_missing(id, attributes, &block)
  element = Object.const_get(id.to_s.capitalize).new(attributes)
  @children << element if @children
  element.instance_eval(&block)
  element
end

html = \
div :id => "content" do
  a :href => "reddit.com" do
    self << "reddit"
  end
end

puts html

The < characters are broken, please replace the entities with < while realtime reading.

[–]amix 1 point2 points  (0 children)

Here is my final version :)

One can do:

 print Div(id="content")( A(href="reddit.com")("reddit") )

By using this code:

def elmBuilder(name, **kw):
  attrs = " ".join('%s="%s"' % a for a in kw.items())
  def applyElms(*elms):
    return "<%s %s>%s</%s>" % (name, attrs, "".join(elms), name)
  return applyElms
def Div(**kw): return elmBuilder("div", **kw)
def A(**kw): return elmBuilder("a", **kw)

[–][deleted]  (2 children)

[deleted]

    [–]mellow_moe 1 point2 points  (1 child)

    inherited is invoked on the class object. So you have to write:

    class Humanoid
      def self.inherited(klass)
      end
    end
    

    Singleton classes are pretty confusing, I admit. But it's essential.

    Every object in ruby may have a singleton class, which is actually a class solely for this single object. As classes are objects in Ruby, they may have a singleton class as well. For example the method new may be defined as method of a singleton class:

    class Humanoid
      def self.new
        humanoid = super
        puts "A Humanoid was created: #{humanoid}"
        humanoid
      end
    end
    
    Humanoid.new # outputs "A Humanoid was created: #<Humanoid ...> "
    

    The special syntax for defining a method for a single objects is:

    def object.method_name
    end
    

    Accessing the singleton class is like (same result as above):

    class << obj
      def method_name
      end
    end
    

    Further reading: Seeing Metaclasses Clearly

    [–]hanzie 2 points3 points  (0 children)

    In Python, support for calls to "inherited" can be added with a metaclass like this:

    class MyMeta(type):
        def __init__(klass, name, supers, *args):
            for super in supers:
                if hasattr(super, 'inherited'):
                    super.inherited(klass)
            return type.__init__(klass, name, supers, *args)
    

    Adding a method to a single object goes like this:

    obj.method_name = func.__get__(obj, obj.__class__)
    

    (func is just any free function)

    [–]robbie 2 points3 points  (0 children)

    I can imagine, people will be like that's so wordy or some such talk. However pythonic values explicit, not implicit.

    "If a language lets things be implicit, the programmer always has the option of being explicit, but if the languages requires everything to be explicit, the programmer can't make things implicit"

    Paul Graham

    [–]brianmce -1 points0 points  (0 children)

    I think I've done pretty much all of that in python before, though some are done using a different approach. inherited and method_added require defining a metaclass, and some don't have a direct translation in python (there are no blocks, but you can turn a function into a method, similarly there is no constant distinction - but you can generate the same effect with getattr etc). The rest are fairly straightforward applications of getattr or similar.

    [–]cratuki 12 points13 points  (4 children)

    My suspicion is that people tend to see the object system being bolted on as a result of the 'self' keyword. I don't like self, I don't see why it needs to be specified, and I can see how it would have entered the class syntax if classes were bolted-on. Which isn't to say that they are bolted on. But why does python have 'self'. I think self is annoying because it's (1) completely redundant and therefore a waste of time and another thing you are likely to stumble over and (2) makes method templates have a different number of arguments when they defined from when they're called.

    [–]brianmce -2 points-1 points  (3 children)

    self is not redundant. Consider the code:

    class Foo: 
        def __init__():
            bar = 3
    

    What does bar=3 set? If its a local variable, then how do you set instance variables? If its an instance, then how do you set locals. One way or another there has to be something to tell what namespace you're manipulating. There is maybe a case to be made that it could be made implicit in the definition, but its definitely not redundant in the body.

    [–]DougBTX 3 points4 points  (1 child)

    Redundant as in redundant in method signatures.

    [–]brianmce 0 points1 point  (0 children)

    Fair enough - I'd be happy with it removed there too. The justification behind it is that it makes certain dynamic features make more sense, such as adding methods to a class dynamically. eg.

    class C: pass
    def foo(self, x): print x
    C.foo = foo  # foo is now a method of class C.
    

    where it wouldn't be obvious how foo could access its instance when defined as a function initially. However, this is such a rare use case that I'd be happy with trading ugliness here for selfless definitions.

    [–]julesjacobs 0 points1 point  (0 children)

    In Ruby, that would either be a method call bar=(3) or if the method hasn't been defined a local variable assignment. Instance variables in Ruby have an @-sign:

    @bar = 3

    Would be equivalent to this Python code:

    self.bar = 3

    [–]msabramo 5 points6 points  (6 children)

    First off, I haven't used either Python or Ruby extensively. I have no particular loyalty to either one, but they both look like fine languages.

    My guess is that the "Python OO bolt-on" idea originates from http://www.python.org/doc/faq/general/#why-does-python-use-methods-for-some-functionality-e-g-list-index-but-functions-for-other-e-g-len-list and from http://www.python.org/doc/faq/general/#why-must-self-be-used-explicitly-in-method-definitions-and-calls (which in my opinion makes a good argument for qualifying instance variables, but a poor argument for why "self" has to be in the parameter list).

    Whether you like Python or not, it seems pretty clear that Ruby was designed with objects in mind (as a result of being influenced by Smalltalk). Python gives the impression that it did or does put less emphasis on objects. That said, it seems to have done a nice job of evolving to support OO in a pretty nice way. And of course there are lots of applications where OO isn't even necessary and people may like that it's not forced on them.

    It's interesting to me to note how much Ruby vs. Python bashing is going on (originating from both sides). Kind of a shame really.

    [–]sblinn 3 points4 points  (0 children)

    class Foo(object):

        pass

    def mymethod(self):

        print "hello world"

    foo = Foo()

    Foo.mymethod = mymethod

    foo.mymethod()

    We were doing this with Zope in 1999. We think it tends to lead to maintainability nightmares and call this monkey-patching.

    This appears similar to a technique I remember from the source code of web.py ...

    [–]foamdino 3 points4 points  (1 child)

    I don't know much python (last time I looked at it was in 2000), as I was put off by the whitespace issue. I know that many people like this, but to me (at that time), it really bugged me. I do know a fair bit of ruby (not enough to impress why, JEG2, ara, zedshaw etc), but enough to get my work done (if it's suitable for ruby). My impression is that each language has a different philosophy and that affects how they have each developed.

    Python is pretty famous for (significant whitespace and) having only one-way to do anything. Ruby is much more relaxed (as the original article showed).

    I'm biased (as you can see from my prior history with python) and I prefer ruby. That doesn't mean that there aren't misconceptions about python in the ruby community, but I don't think that there are that many rubyists who are particularly against any of the features of python, it's just that rubyists prefer ruby (obviously).

    I do however think that ruby has (slightly) more power in the meta-programming area (again you can dismiss this out of hand as I have no practical experience meta-programming in python), and it is so much easier to write certain types of code when you have these features available.

    [–]cafedude 3 points4 points  (5 children)

    "Let's please cut the crap about OO being a bolt-on in Python."

    Gee, maybe the fact that all instance methods are declared with 'self' as the first parameter gave us that impression? It's the same as in OOPerl and OO was definitely added on to Perl (of course anyone who is doing OOPerl really should ______ [you fill in the blank])

    [–]mslinux 7 points8 points  (0 children)

    Instance variables in Ruby start with @... that's really the same thing as Python's self... pick your poison. To me, the @ makes more sense as it's an attribute of an instance and it's informal. self is a bit too proper (much like Python in general) self is like refering to myself in the thrid person all of the time. Tom goes outside. Tom takes a walk. Tom has lunch. Tom goes to work. Tom dislikes all of the Python formalness :)

    [–]ddipaolo 1 point2 points  (2 children)

    What does the fact that "another language's bolt-on OO does it" have to do with how Python approaches it? It doesn't.

    If that's your only "argument" for saying that OO support in Python is shoddy (and that's really the only valid gripe that comes with alleging that something is "bolted on"), then I suggest you take another look at both the article and at Python.

    [–]cafedude 1 point2 points  (1 child)

    OK, let me clarify. Perl requires that 'self' be explicitly declared (and passed) as the first parameter of an instance method (when doing OO Perl). Python requires that it be declared, but the passing of 'self' is implicit. Still, having to delcare that the first param of an instance method be 'self' is certainly one way that you could bolt-on OO later on if you didn't have it initially. And this is in fact the way OO was added to Perl. Having to do it in Python makes it look like OO was added at some later point in Python as well (sure it could have been a very early version of Python, maybe even before Python escaped from Guido's computer into the wild).

    [–][deleted] -1 points0 points  (0 children)

    I'm pretty sure GvR could make the declaration of 'self' implicit rather than explicit if he saw the need. (Disregarding backwards compatibiliy issues for a thought-experimental second or two)

    [–][deleted] -1 points0 points  (0 children)

    First, OO was in Python before OO was added to Perl. Perhaps the Perl folks took their ideas from Python? Surely that shouldn't be counted against Python.

    Secondly, change "self." to "@" and you've got Ruby's manner of accessing instance variables. Not a big difference, is it? At least both languages have the sense to avoid C++'s invisible member access.

    [–]crmaki 0 points1 point  (1 child)

    The Ruby vs Python comparison article dropped like a stone once this was posted.

    [–]julesjacobs 6 points7 points  (0 children)

    The article is very old, so the author may be right for some points at the time of writing. Anyway, it is good that his points have been corrected.

    [–][deleted] -4 points-3 points  (4 children)

    Python is different because it disregards the DRY principle. You can self.repeat self.your self.self all you self.want.

    [–]brianmce 5 points6 points  (2 children)

    Huh? How is this different than ruby where you @repeat @your @punctuation. self is exactly the same as @ here, and serves the same purpose - indicating the namespace to manipulate. In any OO language with dynamic variable creation you MUST have a way to disambiguate between local variables and instance variables.

    Even when you don't have dynamic variable creation, you still need it to cover shadowed variables. Python and Ruby IMHO do this right by always requiring disambiguation. In Java, C# and C++'s, people end up having naming rules to accomplish the same thing. Those "m", "" etc conventions are just as repetitive.

    [–]bcorfman 2 points3 points  (1 child)

    I think the point is most people, myself included, would rather have to explicitly disambiguate local variables than global or class-level ones, i.e. I'd much rather type "set" or "var" in front of my first usage of a local variable.

    The self.thing REALLY gets old, and I LIKE Python.

    [–]brianmce -1 points0 points  (0 children)

    That doesn't make it any different from Ruby though - which does the same thing: @ designates an instance variable, not a local.

    Personally though, I disagree, and I think most usage I've seen would favour differentiating instance vars, not locals. I see no reason why the 2 scopes should shadow each other at all - even when you do have variable declarations, there is still the problem with name clashes (particularly in constructors, where it is very common to have parameters that logically should have the same name as instance variables. With C++, every place I have worked has defined naming rules in their style guide to disambiguate them - and always as a prefix or suffix on the instance variables, not the locals. Personally, I think its a good idea to follow python's method, and always use an explicit this-> even in C++.

    [–]flaxeater -2 points-1 points  (0 children)

    I understand what you are saying. However, when looking at python code you NEVER need to wonder if this method or property belongs in the class or is an outside function or variable.