On Friday, May 20, 2011 12:58:26 PM Michael Sokol wrote:
> My question is, what kind of mental model do you use when you program in
> Ruby?

I'm not sure of the best way to describe this, and I suspect others have 
already done a decent job, but in any language, I have two main things going 
on in my head. First is the semantics of the language in question. Second is 
just enough of the implementation, usually more closely related to the 
semantics than to the actual C code, that I have an intuition of what kind of 
things are likely to be more or less efficient.

> How do you think about objects? Do you see them as elements carrying
> with them their own methods, bundled with their data?

Not quite, but close. With respect to the object or class I'm currently 
developing, I think of it almost as an independent program capable of sending 
and receiving messages, much as I think of Erlang processes. When using 
objects, I think of them as nouns, and the methods as verbs.

> How about the flow of the program: Whenever there's a method call, do you
> picture the method to be inside the receiver - just like it would be in a
> real-life object -, or since you know that in the underlying implementation
> the method is stored in the class, you just think about a procedure call
> with a self variable being the receiver?

I think of it as being "inside the receiver" in the sense that your 
personality, your decisions, your actions and reactions, are all inside your 
brain. That some might be genetic (and there is of course dispute about this) 
is an irrelevant detail.

There are practical reasons for this, also: How an object responds to a method 
call really is up to the object. Aside from method_missing and other fun 
tricks, objects also have metaclasses, which means you can define a method on 
a single object.

> Do you think using the OOP abstraction without knowing the internals can be
> harmful?

I agree with Robert; worrying about internals when you don't have to is 
harmful. While I do have a thread running in my head thinking about 
performance considerations, even that is irrelevant for most programs most of 
the time.

So, for your case:

> My case for that (even if I tend not to believe so) would be that
> someone might be tempted to think that during an object instanciation, all
> the instance variables AND methods gets duplicated for this particular
> instance, which isn't the case - yet, that's what the abstraction pushes us
> to believe.

If you don't know JavaScript well, I would strongly suggest picking it up. 
Read pretty much anything Douglas Crockford has to say about it, and play with 
different OO patterns. I'm going to use this as an analogy here, so I'll try 
to include enough background that it's understandable if you don't know any 
JavaScript, or if you still think JavaScript is "Java Lite".

JavaScript objects behave like hashes, and the two can be used almost 
interchangeably. Methods are just functions (generally anonymous) which have 
been stored in the hash, and a syntax for calling them which sets 'this' -- 
but you can apply almost any function to almost any object. Many 
implementations allow you to get a method's source easily -- playing around 
with this, it seems that when you attempt to coerce a method into a string, 
you get the source back.

Your choices for inheritance are either to use JavaScript's own prototypal 
inheritance, or to write your own inheritance -- and your only choice for 
multiple inheritance is to roll your own. With prototypal inheritance, any 
time you try to access a property (either an instance variable or a method) of 
a given object, it checks that object first, then its prototype object, then 
the prototype's prototype, and so on, arbitrarily deep.

Rolling your own is much more flexible -- you just create a new, empty object 
(as easy as {}) and start adding methods to it. Basic inheritance would just 
mean calling some "constructor" method which returns an object, then modifying 
it in the child "constructor" method.

Now, like with your example, as a newbie, you might be tempted to think that:
 - Functions are stored as strings.
 - Internal, inline functions are therefore inefficient, because you're 
creating a new string each time.
 - Prototypal inheritance is slow, especially at any depth, since you'll have 
to trace the entire ancestry for each access.
 - Roll-your-own inheritance is tremendously inefficient, since even if the 
initial object creation (prototypal or otherwise) was efficient, you're taking 
the child and modifying it, thus leading to worse performance.

One of these is still true, but the others are false. Most surprisingly, 
rolling your own inheritance _may_ lead to a slower constructor -- maybe -- 
but in the v8 engine (used in Chrome), there's no performance penalty 
whatsoever once the objects are created. Despite the highly dynamic nature of 
what I'm calling roll-your-own inheritance, which feels like it should be less 
efficient than calling Object.extend in Ruby on every single object, the 
resultant objects behave very similarly to objects created in statically-typed 
languages -- that is, they're fast!

I just wrote several paragraphs setting up the problem and explaining why it's 
not a problem. That is why I think while internals are a great learning 
experience, a best practice is to ignore implementation details, particularly 
performance implications, until you actually care.

That, and think bigger. Suppose it was true that all the instance variables 
and methods got duplicated for a given instance. So what? It's still O(1) with 
regard to the algorithm I actually care about, unless that algorithm consists 
of adding methods to the parent class based on input and then creating a bunch 
of objects.