Discussion: Lecture 3

September 13th, 2009 Leave a comment Go to comments

Add comments here with questions and notes regarding Lecture 3.

  1. Gabriel Hase
    September 15th, 2009 at 07:56 | #1

    Concerning Single inheritance & mixins (as in the Pickaxe chapter 5):

    After reading the chapter 5 from the pickaxe I was a bit confused in what way mixins are better than multiple inheritance (which I know from C++). After all method and variable name clashes are still possible.
    If found an article on the web that drew a bit closer on the advantages:
    http://www.oreillynet.com/ruby/blog/2007/01/digging_deep_mixing_it_up_or_i_1.html

    For me the strongest point is the clean distinction of "is-a" and "has-a" or "can-do". (which is more of a theoretical concept to be honest)

    Matz's statement "mixins could do almost everything multiple inheritance do, without the associated drawbacks" is to my understanding a bit of an exaggeration... after all there are still some of the drawbacks present.

    Also with this level of class-designer responsibilty I am missing the compiler warning help that I get in C++.

    An example:

    class Test
    include Enumerable
    end

    t1 = Test.new
    t2 = Test.new
    if t1>t2 then puts "t1 is bigger" end

    This will crash with an exception at run-time.

    Are there tools that I can run against my code that would tell me something along the lines of:
    Warning: Test is not declared to be Enumerable. Implement the operator.

    Does anyone have links to interesting and thourough discussions on the topic mixins vs. multiple inheritance? (a google search give trillions of results...)

  2. September 15th, 2009 at 09:43 | #2

    @Gabriel Hase

    I haven't lectured on classes, modules, testing, or the philosophy behind it, yet, but here are a few notes.

    Incidentally, you get the < operator from including Comparable and implementing <=> not via Enumerable / each.

    The only reason you WOULD include Enumerable is to obtain the benefits of its methods which depend on an implementation of each; so your example is pretty far-fetched. To be sure, someone might do it -- but since in this course I will say things like "read the documentation - if you want to include Enumerable, make sure to implement each," this problem won't happen to you, at least. :-)

    [It is probably more likely that you'd implement each, and then wonder why you're not getting the benefits of Enumerable (oops, I forgot to include Enumerable!). It would be rather pushy for a code-studying tool to make that kind of judgement, yes?]

    The mere presence of a method called "each" isn't going to get you very far. After all, the exact implementation of each is *up to you*. "each" might yield the "next" item in any number of different ways, depending on your class. I want to repeat this with a lot of emphasis: Merely HAVING AN EACH METHOD means little, because the semantics of that each method are up to you. "Implementing the operator" would not help your code satisfy whatever requirements you have for your own each. Only a test can assure yourself and other developers that you've implemented your each properly. So, if this is important code (and what code isn't important?), you'd write a test, and the test would fail without each; indeed, in a test-first methodology, you would want it to fail as a first step before implementation. Plus, as you can see, Enumerable "fails fast"; if it got deployed, you'd see the problem right away.

    The code tool you imagine would have to be extremely sophisticated. Suppose you have a class Test which includes Enumerable, but for a variety of reasons, you don't plan to instantiate it, because in your design only *subclasses* of Test will implement each. How would the code tool know that only the subclasses should be checked? This is just the tip of the iceberg. Suppose the tool was able to tell you that you had implemented each. Does that mean you're safe? Not at all. I have heard that some C++ programs still have bugs, even though the compiler does a lot of checking in advance.

    Now, mixins vs. multiple inheritance (MI): I am not going to mount a strong defense of mixins as opposed to MI. You are probably right that Matz is exaggerating. The driver for alternatives to MI is the dissatisfaction some developers feel, largely because in practice they find conflicts between classes they want to adapt/use. Matz is also rather modest: He says mixins can do "almost" everything MI can do. So I guess the comparison would really have to get down to cases (e.g., let's see some Ruby classes with modules that are somehow limited compared to what you can do in C++'s MI model).

    In Ruby, there are rules governing which methods are in play in your class hierarchy, so "clashes" are unusual, because you control the order in which modules are included. Ruby class hierarchies tend to be very shallow as well; in my experience, it's pretty unusual to have an issue.

  3. Gabriel
    September 18th, 2009 at 12:50 | #3

    for all who were a bit puzzled about the "class << foo" syntax in the pickaxe chapter 22 reference to classes, here is a good link that explains the deal:
    http://ola-bini.blogspot.com/2006/09/ruby-singleton-class.html

    I skipped the part about metaprogramming since I don't know anything about it yet. But it explains quite well how static functions work in ruby (and why its called a singleton class).

    The post is quite old. Can someone confirm that this is still the way it works with Ruby 1.9?

  4. September 18th, 2009 at 13:08 | #4

    @Gabriel

    That's still the way.

  5. Gabriel
    September 18th, 2009 at 13:49 | #5

    I put the code from the pickaxe, chapter 22, page 325/326 on class variables in a file to test it. On execution the last call to a.get_var returns 123 on my ruby (1.9.1)! In the book it says that it should return "top level"... an error in the book or a change in ruby?
    Considering the behavior of class variable I can only agree with the recommendation of not using them...

    here is my code:

    BEGIN{
    class Holder
    @@var=99
    def Holder.var=(val)
    @@var=val
    end
    def var
    @@var
    end
    end

    @@var="top level"
    a = Holder.new
    puts a.var
    Holder.var = 123
    puts a.var

    def a.get_var
    @@var
    end
    puts a.get_var
    }

  6. September 18th, 2009 at 13:59 | #6

    Put ONLY this code (leave out the BEGIN and the def a.get_var) into a file, e.g., pickaxe.rb, and then do ruby pickaxe.rb - I get "top level":

    class Holder
    @@var=99
    def Holder.var=(val)
    @@var=val
    end
    def var
    @@var
    end
    end

    @@var="top level"
    a = Holder.new
    puts a.var

  7. Gabriel
    September 18th, 2009 at 14:06 | #7

    @john
    On the first statement (puts a.var) I get "top level" too. But the example in the book goes on with the code I wrote above.
    And on the third statement (puts a.get_var) I get 123 and not "top level" like in the pickaxe. The output is the same in irb or executed from a file. Just to be complete the output to my 3 puts above is:

    top level # same as pickaxe
    123 # same as pickaxe
    123 # different!

  8. September 18th, 2009 at 14:15 | #8

    @Gabriel

    Ah.

    I get the same results.

    I'll try and figure out what the problem is. Gabriel, would you be able to check the errata page for the Pickaxe at pragprog.com? Also, in the PDF, this is on p. 337-338.

    Just FYI, my strategy for lecture is to discuss the use of @@-scoped variables last (after we've talked about class instance variables). I avoid @@-scoped variables altogether. I don't even like calling them "class" variables.

  9. Gabriel
    September 18th, 2009 at 14:29 | #9

    @john
    It's already in the errata under #39185. Same behavior that we had.

  10. Ron Newman
    September 18th, 2009 at 17:56 | #10

    Is this considered an error in the book, or erroneous behavior by the Ruby interpreter?

  11. September 18th, 2009 at 21:09 | #11

    @Ron Newman

    It seems to be a change in Ruby 1.9.1: One comment says that the output is consistent with a build of 1.9.0.

    I will study it.

  12. Ron Newman
    September 21st, 2009 at 15:04 | #12

    The very next example on that Pickaxe page (338 of the PDF), I find utterly baffling. "Class variables are inherited by children but are unique across children:" is a sentence I'm having a lot of trouble understanding.

  13. September 21st, 2009 at 15:29 | #13

    @Ron Newman

    I have read that sentence before; I don't think it makes any sense.

    It should say: "Class variables are available to children."

    I would have to re-read the whole discussion, but there should be advisories that point out that class variables (@@) are quasi-global, and on that basis alone, should be avoided.

  14. Gabriel Hase
    October 1st, 2009 at 02:50 | #14

    I have a problem with a title in the pickaxe. On page 393 (print) it says "Creating Singleton Classes" and then examples like the following:
    some_class = Class.new do
    ...
    end

    a = some_class.new

    To my understanding some_class cannot be a Singleton Class since before in the same chapter it was stated clearly that Singleton Classes cannot be instantiated (which also make a lot of sense). So the classes I create with Class.new are not Singletion Classes, right?

  15. October 1st, 2009 at 06:39 | #15

    @Gabriel Hase

    It is not clear.

    What he means is this:

    When you run Class.new, you are creating an object of the class Class. There is only one such object. If, on that object, you define "self" methods, they will be singleton methods in the sense described on p. 377, and, implicitly, the eigenclass (aka singleton class) is in play.

    So, to my reading, p. 393 is missing a paragraph that would put the emphasis on classes_36.rb and its "def self.class_method".

  16. Ron Newman
    October 1st, 2009 at 23:10 | #16

    It would probably be a good idea at this point to create a new Discussion for Lectures 4 and 5.

  17. October 1st, 2009 at 23:45 | #17

    @Ron Newman

    Good idea.

  18. Michael McLawhorn
    October 25th, 2009 at 08:28 | #18

    I'm having trouble using the correct password to get into the site. I've consulted my email and I'm pretty sure I'm using the correct password. Is the e168 account disabled at the moment?

  19. October 25th, 2009 at 09:46 | #19

    @Michael McLawhorn

    I will send you an e-mail.

  1. No trackbacks yet.