[suby-talk] "Is" and ideas for moving foward

Peter Vanbroekhoven calamitas at advalvas.be
Sat Sep 24 18:18:17 EDT 2005


On Sat, 24 Sep 2005, TRANS wrote:

> Today George of Nitro asked me to alias #include to #is:
>
>  class Foo
>    is Bar
>  end

I like this too. It's very nice for things like Enumerable:

   class Foo
     is Enumerable
   end

If the name of a module is a noun, #is_a and #is_an are nice to. And if 
you're afraid of people accidentally overriding these methods, you can 
also alias it to #walks_and_quacks_like_a ;-) Actually, I'm not completely 
joking about this, it is one of those nice details that can make code more 
fun to read!

> I like it and saw no ready reason now to support it so I added it to
> Nano. This got me to thinking about how modules are included. I really
> tire of jumping through hoops using Module#included to tell it I want
> class method included too. The use of #extend seems backward --why
> should the class dictate how the module effect it? (except under
> special circumstances). I think that undermines the whole idea of
> "enpsulated module".
>
> So I propose we get on with it and offer some declarations:
>
>  module M
>  function
>      def f ; "F" ; end
>  extends
>      def x ; "X" ; end
>  inherits
>      def y ; "Y" ; end
>  end
>
> 'function' is the same as current module_function and would be the
> default. It both acts as a non-extending module function and an
> instance-level inheritable. So,
>
>  M.f  #=> "F"
>  M.x  #=> error
>  M.y  #=> error
>
>  class X
>    is M
>  end
>
>  X.x      #=> "X"
>  X.new.y  #=> "Y"
>  X.f      #=> error
>  X.new.f  #=> "F"  (albeit  it is private)

You know, maybe we can look at this slightly differently. At the moment, 
this works:

   class A
     def x ; "x" ; end
     def self.y ; "y" ; end
   end

   class B < A ; end

   A.new.x
   A.y
   B.new.x
   B.y

Why does this work? Because this is true:

   B.is_a? A.metaclass

What does this mean? It means that B's metaclass is a subclass of A's 
metaclass, although they've tried to cover up this fact. For example 
B.metaclass.superclass will return Class.metaclass and not A.metaclass, 
but A.metaclass is there in the chain. (You should remember that picture). 
Now why oh why is the same thing not done on module inclusion? It seems to 
make sense to do it, right? And it would solve part of your problem. Of 
course it is not as powerful as your proposal above, but it goes part of 
the way and is simpler, so I say do it like that and build extra 
functionality on top of that.

Also, if you want to go the above way, please let these new functions have 
block forms too, or only block forms as far as I'm concerned. I find the 
way things are now for private and all too magical, and also emacs will 
indent better. So IMO the above would look better like this:

   module M
     function {
       def f ; "F" ; end
     }
     extends {
       def x ; "X" ; end
     }
     inherits {
       def y ; "Y" ; end
     }
   end

Sure it adds a few more lines, but I find this a lot clearer.

> Also I would like to move foward on ultimately replacing the #methods
> and #instance_methods to take symbol query parameters, instead of have
> all the other methods: public_methods, private_methods, etc. In fact
> if methods tool on more of a 1st class role (even if faked). Then
> perhaps:
>
>  M.methods.select { |m| m.access == :private }
>
> Of course I still am interesed in throwing out the current
> private/protected/public for now and start fresh later with a truer
> form.

Well, I think it would still be nice for public_methods etc to remain, but 
just add a deneral select method (possibly even just as Module#methods). 
The reason is that IMO these are still generally useful methods. I usually 
only need either public_methods, or private_methods, or 
public_instance_methods, and it makes little sense to all of a sudden have 
to write twice as much code to do the same thing.

> Finally, I'm curious. And I know this might seem like a shocker. But I
> often wonder about the fact the #alias doesn't need a comma separated
> list of arguments. I know it's special but I wonder if it might be
> generally applicable?
>
>  class X
>    def intialize( a b c )
>      #...
>    end
>  end
>
>  X.new :A :B :C

Well, it causes ambiguity. "a b c d" can be parsed as follows:

   a(b(c(d)))
   a(b(c,d))
   a(b(c),d)
   a(b,c(d))
   a(b,c,d)

Of course, if you don't want commas, you could always employ a Lispy kind 
of syntax:

   (X.new :A :B :C)

Or else require brackets around the parameters at all times:

   X.new(:A :B :C)

I don't think you can get away with dropping these commas without 
introducing extra brackets, or some other way of disambiguating thing.

Peter


More information about the suby-talk mailing list