Prototype-based / Ruby question

(Jonas Pfenniger) #1

I just stumbled across this page[1] on RubyGarden. The writer tells
that prototye-languages languages are great and that Ruby is not part
of them.

As I understand the definition, prototype based languages don't
instanciate objects from a class, but rather clone an existing model
object. Ruby's classes are objects.

So which is first, the Class or the Object ?

It makes me think of a french sentence which says : From the chicken
and the Egg, which was first ? (disregarding the theory of evolution)

Cheers,
.... zimba

[1] http://rubygarden.org/ruby/ruby?action=browse&id=PrototypeBasedRuby

(Robert) #2

I just stumbled across this page[1] on RubyGarden. The writer tells
that prototye-languages languages are great and that Ruby is not part
of them.

As I understand the definition, prototype based languages don't
instanciate objects from a class, but rather clone an existing model
object. Ruby's classes are objects.

But they are not cloned:

class Foo;end

=> nil

o=Foo.new

=> #<Foo:0x1018f918>

Foo.class == o.class

=> false

o.class == o.dup.class

=> true

o.class == o.clone.class

=> true

So which is first, the Class or the Object ?

In fact it's a circular dependency. The Ruby interpreter precreates
certain objects, among them Object, Class and Module. From the
perspective of a Ruby program it doesn't matter which of them was first -
they are simply there as a connected graph of objects with a cycle. :slight_smile:

It makes me think of a french sentence which says : From the chicken
and the Egg, which was first ? (disregarding the theory of evolution)

The cat.

[1]
http://rubygarden.org/ruby/ruby?action=browse&id=PrototypeBasedRuby

Kind regards

    robert

···

zimba.tm@gmail.com wrote:

(Gavin Kistner) #3

From research on the web, it appears that the above definition is the commonly-held one. I had always thought that 'prototype-based' referred to the object-chaining available in languages like Javascript (where the chain uses the word 'prototype') or Lua (the __index metatable property). Is there another term to cover this sort of 'inheritance'? Or is this an important aspect of prototype-based languages for representing inheritance?

[Non-Ruby Code Samples Follow]
For those who don't know what I'm talking about, the following JavaScript and Lua examples show how you can make simple 'instance' objects have access to a common 'class' object, including changing the methods and properties on that class after instantiation.

JavaScript:
Mammal = function( ){
   this.isAlive = true;
}
Mammal.prototype.hasHair = true;
Mammal.prototype.die = function( ){
   this.isAlive = false;
}

Person = function( inName ){
   this.name = inName;
}
Person.prototype = new Mammal;
//other 'best practice' inheritance details omitted for clarity
Person.prototype.toString = function(){
   return "[Person '"+this.name+"']";
}

var gk = new Person( "Gavin Kistner" );
gk.nickname = "Phrogz"; // instance property
alert( gk ); // [Person 'Gavin Kistner']
alert( gk.isAlive ); // true
alert( gk.hasHair ); // true
Person.prototype.eat = function(){
   if ( !this.weight ) this.weight = 170;
   this.weight += 1;
}
gk.eat( );
alert( gk.weight ); // 171
gk.die( );
alert( gk.isAlive ); // false

In the above, when gk.hasHair is referenced, JavaScript looks:
   * In the gk object for a hasHair property
   * In the constructor's (Person) prototype object for a hasHair Property
   * In the constructor's prototype's prototype object for a hasHair Property (where it is found)

When the die() method is invoked on gk, it is found on the Mammal prototype, but 'this' is still the gk object. While reading the value of 'isAlive' on gk searches up the prototype chain for that property, setting the value creates a new property on the gk object itself.

Lua:
Mammal = {
   isAlive = true, --by default, overridden per instance if needed
   hasHair = true,
   die = function( self )
     self.isAlive = false
   end
}

Person = {
   new = function( inClass, inName )
     local instance = { name = inName }
     setmetatable( instance, inClass.inheritTable )
     return instance
   end,
   proto = {
     -- empty to begin with
   },
   inheritTable = {
     __tostring = function(self) return "[Person '"..self.name.."']" end
   }
}
Person.inheritTable.__index = Person.proto
--inherit properties from Mammal
setmetatable( Person.proto, { __index = Mammal } )

local gk = Person:new( "Gavin Kistner" )
gk.nickname = "Phrogz"

print( gk ) --> [Person 'Gavin Kistner']
print( gk.isAlive ) --> true
print( gk.hasHair ) --> true
Person.proto.eat = function( self )
   if not self.weight then self.weight = 170 end
   self.weight = self.weight + 1
end

gk:eat( )
print( gk.weight ) --> 171
gk:die( )
print( gk.isAlive ) --> false

In Lua, every 'table' (hash object) can have another 'metatable' associated with it. While the table holds information about the object itself, the metatable holds information about that object's inheritance chain, string conversion, operator overloading, and more. If Lua cannot find a property for an object in the object's table, it sees if the object has a metatable with an __index property pointing to another table; if so, it asks that table for the value.

Like the JS example, the Lua above has three main objects - the gk table, the Person.proto table, and the Mammal table. (The Person table itself is a nice namespace wrapper for the proto, new, and inheritTable properties.) Like JS, any number of Person instances can be created, and they will all share common 'eat' and 'die' methods from their ancestors.

In both of the above cases, a full-fledged instance with all the methods is not copied upon creation, but instead a lightweight instance is created with pointers that the language can use to find 'inherited' methods or properties.

···

On Aug 17, 2005, at 2:21 AM, zimba.tm@gmail.com wrote:

As I understand the definition, prototype based languages don't
instanciate objects from a class, but rather clone an existing model
object. Ruby's classes are objects.

(Lionel Thiry) #4

zimba.tm@gmail.com a écrit :

I just stumbled across this page[1] on RubyGarden. The writer tells
that prototye-languages languages are great and that Ruby is not part
of them.

As I understand the definition, prototype based languages don't
instanciate objects from a class, but rather clone an existing model
object. Ruby's classes are objects.

So which is first, the Class or the Object ?

It makes me think of a french sentence which says : From the chicken
and the Egg, which was first ? (disregarding the theory of evolution)

Cheers,
... zimba

As far as I could understand it, the most practical advantage of
prototype based OO language is their ability for one object to
dynamically rewrap its inheritence. Oh, in protope based language,
inheritence is named delegation. But it is same in the sense that both
affect the lookup.

Is it possible to do self.class = OtherObject ? I don't know, I haven't
tested it yet, but I guess it is "no". Is it possible to dynamically
un-include and include Module in a class? Perhaps, I'm not sure. But if
it is, then Ruby is not that much less than a prototyped language after all.

Or I just don't get it about prototype based language. I must tell that
I'm not even sure to understand what typing could be in ruby, and I
don't even tell about duck typing.

···

--
Lionel Thiry

Personal web site: http://users.skynet.be/lthiry/

(Lyndon Samson) #5

I'd say prototype means no classes, that is create an Object from another (
Including Object ) and munge it at will, add/remove/change behaviour or
variables.

I wonder if Ruby2 really needs classes? They seem to be de-emphasised in the
Ruby world ( the one eyed duck is king ) and the other use for class like
concept is interfaces which there seems to be alot of hostility towards.

(Florian Gross) #6

Lionel Thiry wrote:

Is it possible to do self.class = OtherObject ?

It is, after you implement it. See http://rubyforge.org/projects/evil/

Is it possible to dynamically
un-include and include Module in a class?

Not in the general case, but there is Module#remove_method.

(David A. Black) #7

Hi --

I'd say prototype means no classes, that is create an Object from another (
Including Object ) and munge it at will, add/remove/change behaviour or
variables.

I wonder if Ruby2 really needs classes? They seem to be de-emphasised in the
Ruby world ( the one eyed duck is king ) and the other use for class like
concept is interfaces which there seems to be alot of hostility towards.

Duck typing co-exists peacefully with the existence of classes -- or
at least it can. The biggest problem I've seen over the years in the
matter of understanding Ruby's particular class/prototype blend is the
"class == type" fallacy. There are two common consequences of this
misunderstanding. First, it leads to the creation of new ways of
referring to type (like "duck type", which is redundant and
superfluous). Second, and sort of the opposite, it leads to the
impression that there's something arcane, wizardly, "evil", and/or
just plain bad about modifying objects during runtime so that their
type is not the same as the type they started out with.

I go for the simplest, most direct account, with no villains in the
story:

A class launches an object into object-space. Thereafter, the object
has nothing to do directly with its class. It *remembers* its class,
but it is not constrained by its class.

Instead, an object has a *type*. (Not "duck type"; just "type".) An
object's type can change and evolve during runtime. Because of this
-- that is, both because this is a constant, pervasive, axiomatic
aspect of Ruby, and because it's a source of useful programming
techniques -- it makes sense to treat an object principally on the
basis of its type, rather than its class. Duck typing encapsulates
this approach.

David

···

On Wed, 17 Aug 2005, Lyndon Samson wrote:

--
David A. Black
dblack@wobblini.net

(Brian Mitchell) #8

Hmm. I think it would be a _very_ bad idea. Prototypes would make
ruby's internals too fuzzy with non definition. Example: It is hard to
write a one size fits all library in Io. We have a common set of
idioms, but our code has nothing to lean on so many of these
primitives have to be built first before use. However, I might throw
in a mode for the with IoRuby. Too much of the core would have to
change so I am not sure if it would even be worth the change.

Brian.

···

On 8/17/05, Lyndon Samson <lyndon.samson@gmail.com> wrote:

I'd say prototype means no classes, that is create an Object from another (
Including Object ) and munge it at will, add/remove/change behaviour or
variables.

I wonder if Ruby2 really needs classes? They seem to be de-emphasised in the
Ruby world ( the one eyed duck is king ) and the other use for class like
concept is interfaces which there seems to be alot of hostility towards.

(Jonas Pfenniger) #9

I'm happy my initial message generated so much participation. That's
what I like in this community. People are nice and curious :slight_smile:

Thank you,
.... zimba

(Eric Mahurin) #10

Hi --

> I'd say prototype means no classes, that is create an
Object from another (
> Including Object ) and munge it at will, add/remove/change
behaviour or
> variables.
>
> I wonder if Ruby2 really needs classes? They seem to be
de-emphasised in the
> Ruby world ( the one eyed duck is king ) and the other use
for class like
> concept is interfaces which there seems to be alot of
hostility towards.

Duck typing co-exists peacefully with the existence of
classes -- or
at least it can. The biggest problem I've seen over the
years in the
matter of understanding Ruby's particular class/prototype
blend is the
"class == type" fallacy.

Using the term "type" by itself instead of something else helps
perpetuate this fallacy. Object#type is a synonym of
Object#class.

There are two common consequences
of this
misunderstanding. First, it leads to the creation of new
ways of
referring to type (like "duck type", which is redundant and
superfluous).

Your definition of "type" is quite different from the
definition I gave of "duck type". Your definition of the
"type" of an object is the "sum of all of its capabilities" -
i.e. ALL of the methods it responds to. I think that
definition is about as relevant to ruby and duck-typing as
class is. This definition of "type" is close to a java
"interface", but is more restrictive because it represents the
entire behavior of an object where an interface may be just a
subset. From your definition of "type", an object only has
one "type" for any given state of that object.

The definition I gave of "duck type" allows an object to have
many "duck types" at a time. It all depends on who is using
the object. Each usage of an object may have a different view
of what the "duck type" is. My definition of "duck type"
really refers to the usage of an object not the object itself.
The most common usage would be as a method argument, but it
could also be applied to variables, using return values from
methods, etc. I think the broadest definition I could give
would be that a "duck type" of a given usage of an object is
described by what capabilities are used of that object in that
context. This includes what methods that object needs to
respond to, the arity of those methods, the "duck type" of the
arguments for those methods, and the "duck type" of what is
returned from those methods.

Take a look at the original definition of duck-typing given by
Dave Thomas. Here is the example he gave:

When I write

    fred << "dog"

in Ruby, I don't care whether fred is a String, a File, or an

Array

In this context, the "duck type" of fred is something that
reponds to <<(aString).

By your definition of "type" being "the sum of all of its
capabilities", you'd have to pick what "type" fred is -
String-like, File-like, or Array-like. If you said that fred
was something File/IO-like you could use an IO, File, or
StringIO for fred, but not a String or Array because they don't
have the same capabilities.

The downside of typing your arguments using this "duck type"
definition is that you have to pick what methods you want to
use up front and document what you are using (or may use). If
you later want to change the implementation to use other
methods, you'll need to change the docs and possibly break
callers using objects under the original duck-type. With the
"type" definition you have, this downside doesn't exist. A
method has much more freedom of choice. For example, in the
above, you could change it to fred.write("dog") later down the
road if you limited fred to be anything IO-like.

So, if you want to give maximum freedom of choice to the
caller, you should describe your arguments with duck-types and
if you want to give maximum freedom of choice to the method
implementor, you should describe your arguments with David's
definition of "type".

Second, and sort of the opposite, it leads to
the
impression that there's something arcane, wizardly, "evil",
and/or
just plain bad about modifying objects during runtime so that
their
type is not the same as the type they started out with.

The biggest problem I have with being able to add/remove/modify
methods of an object (using a meta class or directly in the
object's class) is the future of optimization in Ruby. Adding
methods may not cause too much of an issue, but modifying them
sure could. For example:

i = 0
i += 1

In this case, Ruby could recognize that i is always a Fixnum
(or a Bignum depending on how smart it is). If it knew exactly
what "+" was for a Fixnum, it would be able to in-line that C
call (in this hypothetical Ruby compiler). Unfortunately, "+"
could be anything since it can change at run-time.

To me, this is an extreme case of methods that mutate the
object. If one thinks #reverse! is bad compared to #reverse
(which I don't) because it mutates the object rather than
returning a new one, being able to modify the methods of an
object (or objects if for a whole class) should seem hideous.
Personally, I don't think adding methods are too bad, but being
able to remove or modify methods doesn't seem like a good idea
or serve much use. I'd rather see a new object be created that
have these methods removed/modified instead.

···

--- "David A. Black" <dblack@wobblini.net> wrote:

On Wed, 17 Aug 2005, Lyndon Samson wrote:

____________________________________________________
Start your day with Yahoo! - make it your home page

(Ron M) #11

Eric Mahurin wrote:

The biggest problem I have with being able to add/remove/modify
methods of an object (using a meta class or directly in the
object's class) is the future of optimization in Ruby. Adding
methods may not cause too much of an issue, but modifying them
sure could. For example:

i = 0
i += 1

In this case, Ruby could recognize that i is always a Fixnum
(or a Bignum depending on how smart it is). If it knew exactly
what "+" was for a Fixnum, it would be able to in-line that C
call (in this hypothetical Ruby compiler). Unfortunately, "+"
could be anything since it can change at run-time.

Seems like the same issue Java and Self compilers have
when new classes are loaded.

There are Java compilers that optimize method calls by
inlining them, and then "dynamically deoptimize" those
if a derived class that changes the meaning of that
inlined code is loaded.

Here's one paper on such dynamic de-optimization:
   http://research.sun.com/self/papers/dynamic-deoptimization.html

Isn't the real challenge your hypothetical "could recognize
that i is always a Fixnum" condition. If the ruby compiler
could do this, couldn't that same logic recognise that it is
always a pristine, unmodified Fixnum. Knowing the type sounds
to me like the hard part of the problem. IIRC Lisp added
optional type declarations to the language that you can
use inside performance critical areas like tight-loops.

(David A. Black) #12

Hi --

Duck typing co-exists peacefully with the existence of
classes -- or
at least it can. The biggest problem I've seen over the
years in the
matter of understanding Ruby's particular class/prototype
blend is the
"class == type" fallacy.

Using the term "type" by itself instead of something else helps
perpetuate this fallacy. Object#type is a synonym of
Object#class.

Yes, but that use is deprecated. The explanation given by Matz in the
past, as I recall, is that he chose to add the synonym "type" because,
at the time, there were problems parsing "class" as a non-keyword,
even in method-call position.

It's unfortunate that that happened, because it's certainly fanned the
flames of the misunderstanding, but it was for understandable
technical reasons and hopefully it will be resolved so that "type" can
disappear.

There are two common consequences of this misunderstanding. First,
it leads to the creation of new ways of referring to type (like
"duck type", which is redundant and superfluous).

Your definition of "type" is quite different from the
definition I gave of "duck type". Your definition of the
"type" of an object is the "sum of all of its capabilities" -
i.e. ALL of the methods it responds to. I think that
definition is about as relevant to ruby and duck-typing as
class is. This definition of "type" is close to a java
"interface", but is more restrictive because it represents the
entire behavior of an object where an interface may be just a
subset. From your definition of "type", an object only has
one "type" for any given state of that object.

The definition I gave of "duck type" allows an object to have
many "duck types" at a time. It all depends on who is using
the object.

I would start with your statement and "divide by duck" :slight_smile: An
object's type allows the object to do many things at a time, and be
addressed in many ways. I don't feel the need to have a label for the
subsets. Just ask the object.

(I guess you could call a subset of a type, too, a type. There's no
type police. As long as the object does what you claim for its type,
that's its type.)

Each usage of an object may have a different view
of what the "duck type" is. My definition of "duck type"
really refers to the usage of an object not the object itself.
The most common usage would be as a method argument, but it
could also be applied to variables, using return values from
methods, etc. I think the broadest definition I could give
would be that a "duck type" of a given usage of an object is
described by what capabilities are used of that object in that
context. This includes what methods that object needs to
respond to, the arity of those methods, the "duck type" of the
arguments for those methods, and the "duck type" of what is
returned from those methods.

Take a look at the original definition of duck-typing given by
Dave Thomas. Here is the example he gave:

> When I write
>
> fred << "dog"
>
> in Ruby, I don't care whether fred is a String, a File, or an

> Array

In this context, the "duck type" of fred is something that
reponds to <<(aString).

By your definition of "type" being "the sum of all of its
capabilities", you'd have to pick what "type" fred is -
String-like, File-like, or Array-like.

On the contrary: I *don't* have to pick or describe or find synonyms
for what it is. That's the point: the type is what's there. I don't
even have to name it.

If you said that fred
was something File/IO-like you could use an IO, File, or
StringIO for fred, but not a String or Array because they don't
have the same capabilities.

No, not at all: you're missing the (intentional) circularity -- even
tautology -- of my account of "type". "String-like" is not a Ruby
type. It may be a partial description of a type -- and it may be a
convenient or expedient shorthand for labeling an object's
capabilities -- but it is not a type. An object could be
"String-like", and also be other things. String-like plus those other
things would, essentially, be the object's type.

This is circular because it means that the type of object x is "the
type which is the type of objects whose type is that of object x."

I never have to say that fred is "String-like" or "Array-like" or
"<anything>-like". All I have to do is send messages to fred.
Neither fred nor the caller has to be constrained by aggregations of
behavior into "String" and "Array" and so forth. All that matters is
what happens at the moment of the method call.

The downside of typing your arguments using this "duck type"
definition is that you have to pick what methods you want to
use up front and document what you are using (or may use). If
you later want to change the implementation to use other
methods, you'll need to change the docs and possibly break
callers using objects under the original duck-type. With the
"type" definition you have, this downside doesn't exist. A
method has much more freedom of choice. For example, in the
above, you could change it to fred.write("dog") later down the
road if you limited fred to be anything IO-like.

I personally wouldn't say "anything IO-like" (nor "O-like", though
that might be closer :slight_smile: but rather: anything that responds to
"write". That's *all* that matters. "IO-like" is a secondary
concept, built on top of that. Let's say someone said: "no, it's not
IO-like; I reject that." That person could still send "write" to fred,
as much as you can.

So, if you want to give maximum freedom of choice to the
caller, you should describe your arguments with duck-types and
if you want to give maximum freedom of choice to the method
implementor, you should describe your arguments with David's
definition of "type".

Well, I think Ruby grants its own freedoms. I'm not sure what you
mean by describing arguments "with" my definition of "type". It
sounds very restrictive. I think one should just write programs with
objects that do things. That's pretty much how Ruby will see it
anyway :slight_smile:

[...]

Personally, I don't think adding methods are too bad, but being
able to remove or modify methods doesn't seem like a good idea
or serve much use. I'd rather see a new object be created that
have these methods removed/modified instead.

It comes in handy for class methods :slight_smile:

David

···

On Thu, 18 Aug 2005, Eric Mahurin wrote:

--- "David A. Black" <dblack@wobblini.net> wrote:

--
David A. Black
dblack@wobblini.net

(Florian Gross) #13

Eric Mahurin wrote:

The biggest problem I have with being able to add/remove/modify
methods of an object (using a meta class or directly in the
object's class) is the future of optimization in Ruby. Adding
methods may not cause too much of an issue, but modifying them
sure could.

"Researchers seeking to improve performance should improve their compilers instead of compromising their languages."

-- An Efficient Implementation of SELF, a Dynamically-Typed Object-Oriented Language Based on Prototypes, July 1989

(David A. Black) #14

In fact, I'm happy to report:

$ /usr/local/lib/ruby-cvs/bin/ruby -ve '"".type'
ruby 1.9.0 (2005-08-06) [i686-linux]
-e:1: undefined method `type' for "":String (NoMethodError)

David

···

On Thu, 18 Aug 2005, David A. Black wrote:

Hi --

On Thu, 18 Aug 2005, Eric Mahurin wrote:

Using the term "type" by itself instead of something else helps
perpetuate this fallacy. Object#type is a synonym of
Object#class.

Yes, but that use is deprecated. The explanation given by Matz in the
past, as I recall, is that he chose to add the synonym "type" because,
at the time, there were problems parsing "class" as a non-keyword,
even in method-call position.

It's unfortunate that that happened, because it's certainly fanned the
flames of the misunderstanding, but it was for understandable
technical reasons and hopefully it will be resolved so that "type" can
disappear.

--
David A. Black
dblack@wobblini.net

(Eric Mahurin) #15

Hi --

>
>> Duck typing co-exists peacefully with the existence of
>> classes -- or
>> at least it can. The biggest problem I've seen over the
>> years in the
>> matter of understanding Ruby's particular class/prototype
>> blend is the
>> "class == type" fallacy.
>
> Using the term "type" by itself instead of something else
helps
> perpetuate this fallacy. Object#type is a synonym of
> Object#class.

Yes, but that use is deprecated. The explanation given by
Matz in the
past, as I recall, is that he chose to add the synonym "type"
because,
at the time, there were problems parsing "class" as a
non-keyword,
even in method-call position.

It's unfortunate that that happened, because it's certainly
fanned the
flames of the misunderstanding, but it was for understandable
technical reasons and hopefully it will be resolved so that
"type" can
disappear.

>> There are two common consequences of this
misunderstanding. First,
>> it leads to the creation of new ways of referring to type
(like
>> "duck type", which is redundant and superfluous).
>
> Your definition of "type" is quite different from the
> definition I gave of "duck type". Your definition of the
> "type" of an object is the "sum of all of its capabilities"
-
> i.e. ALL of the methods it responds to. I think that
> definition is about as relevant to ruby and duck-typing as
> class is. This definition of "type" is close to a java
> "interface", but is more restrictive because it represents
the
> entire behavior of an object where an interface may be just
a
> subset. From your definition of "type", an object only
has
> one "type" for any given state of that object.
>
> The definition I gave of "duck type" allows an object to
have
> many "duck types" at a time. It all depends on who is
using
> the object.

I would start with your statement and "divide by duck" :slight_smile:
An
object's type allows the object to do many things at a time,
and be
addressed in many ways. I don't feel the need to have a
label for the
subsets. Just ask the object.

(I guess you could call a subset of a type, too, a type.
There's no
type police. As long as the object does what you claim for
its type,
that's its type.)

> Each usage of an object may have a different view
> of what the "duck type" is. My definition of "duck type"
> really refers to the usage of an object not the object
itself.
> The most common usage would be as a method argument, but it
> could also be applied to variables, using return values
from
> methods, etc. I think the broadest definition I could give
> would be that a "duck type" of a given usage of an object
is
> described by what capabilities are used of that object in
that
> context. This includes what methods that object needs to
> respond to, the arity of those methods, the "duck type" of
the
> arguments for those methods, and the "duck type" of what is
> returned from those methods.
>
> Take a look at the original definition of duck-typing given
by
> Dave Thomas. Here is the example he gave:
>
> > When I write
> >
> > fred << "dog"
> >
> > in Ruby, I don't care whether fred is a String, a File,
or an
>
> > Array
>
> In this context, the "duck type" of fred is something that
> reponds to <<(aString).
>
> By your definition of "type" being "the sum of all of its
> capabilities", you'd have to pick what "type" fred is -
> String-like, File-like, or Array-like.

On the contrary: I *don't* have to pick or describe or find
synonyms
for what it is. That's the point: the type is what's there.
I don't
even have to name it.

From what you said above, I don't see any debate over how I
defined "duck type" (other than the name). I only see you
clarifying what you meant by "type". I still don't see a
concrete definition of yours, but it sounds like you might mean
the same as what I said for "duck type". But, when you say
"type" is "the sum of all of its capabilities" and "an
object's type can change and evolve during runtime" this says
to me your "type" is associated with the object itself and not
how the object is used. All that really matters regarding
"type" in my opinion is how an object is used. What a
particular object's entire capabilities and the fact that they
can change over time is orthongonal.

I'm not sure why you don't like the term "duck type". It is
directly associated with the term "duck typing" and is quite
clear in that context. I don't understand the need to talk
about/document an abstract "type" beyond the context of "duck
typing". Can you think of anything else?

> If you said that fred
> was something File/IO-like you could use an IO, File, or
> StringIO for fred, but not a String or Array because they
don't
> have the same capabilities.

No, not at all: you're missing the (intentional) circularity
-- even
tautology -- of my account of "type". "String-like" is not a
Ruby
type. It may be a partial description of a type -- and it
may be a
convenient or expedient shorthand for labeling an object's
capabilities -- but it is not a type. An object could be
"String-like", and also be other things. String-like plus
those other
things would, essentially, be the object's type.

This is circular because it means that the type of object x
is "the
type which is the type of objects whose type is that of
object x."

I never have to say that fred is "String-like" or
"Array-like" or
"<anything>-like". All I have to do is send messages to
fred.
Neither fred nor the caller has to be constrained by
aggregations of
behavior into "String" and "Array" and so forth. All that
matters is
what happens at the moment of the method call.

> The downside of typing your arguments using this "duck
type"
> definition is that you have to pick what methods you want
to
> use up front and document what you are using (or may use).
If
> you later want to change the implementation to use other
> methods, you'll need to change the docs and possibly break
> callers using objects under the original duck-type. With
the
> "type" definition you have, this downside doesn't exist. A
> method has much more freedom of choice. For example, in
the
> above, you could change it to fred.write("dog") later down
the
> road if you limited fred to be anything IO-like.

I personally wouldn't say "anything IO-like" (nor "O-like",
though
that might be closer :slight_smile: but rather: anything that responds
to
"write". That's *all* that matters. "IO-like" is a
secondary
concept, built on top of that. Let's say someone said: "no,
it's not
IO-like; I reject that." That person could still send "write"
to fred,
as much as you can.

My point was that if you document your method to take an
IO-like object (which I thought was your way - sum of the
capabilities of an object), you have the freedom to use any of
the IO methods. If initially the method is implemented using
<<, it may work with anything that has the << method now, but
you run the risk of something breaking if the implementation
changes to use different or additional methods. If you
document a method like this, you give the method implementation
freedom to use a wide range of methods, but limit the caller to
objects that implement that entire interface.

Of course that is not the duck-typing or ruby way. The
duck-typing way is to document what capabilities you want/need
from an argument and that's it. This gives more freedom to the
caller and less to the method implementation.

> Personally, I don't think adding methods are too bad, but
being
> able to remove or modify methods doesn't seem like a good
idea
> or serve much use. I'd rather see a new object be created
that
> have these methods removed/modified instead.

It comes in handy for class methods :slight_smile:

But, do you ever use the intermediate versions of the class
without the class methods? The way class methods are
implemented now uses a meta class of Class that is modified
along the way. It didn't have to be done that way.

For comparision, look at these two:

x = "Hello world!".reverse # returns a new object

x = "Hello world!".reverse! # modifies existing object

In Java, compare the optimizations that could be done with
String (immutable) vs. StringBuffer (mutable). There are many
optimizations that can be done in String relative to
StringBuffer because it is immutable. I assert the same can be
said of mutable vs. immutable classes (or meta classes), but I
think the difference is more significant once you get deep into
optimizations.

···

--- "David A. Black" <dblack@wobblini.net> wrote:

On Thu, 18 Aug 2005, Eric Mahurin wrote:
> --- "David A. Black" <dblack@wobblini.net> wrote:

____________________________________________________
Start your day with Yahoo! - make it your home page

(Eric Mahurin) #16

Eric Mahurin wrote:
>
> The biggest problem I have with being able to
add/remove/modify
> methods of an object (using a meta class or directly in the
> object's class) is the future of optimization in Ruby.
Adding
> methods may not cause too much of an issue, but modifying
them
> sure could. For example:
>
> i = 0
> i += 1
>
> In this case, Ruby could recognize that i is always a
Fixnum
> (or a Bignum depending on how smart it is). If it knew
exactly
> what "+" was for a Fixnum, it would be able to in-line that
C
> call (in this hypothetical Ruby compiler). Unfortunately,
"+"
> could be anything since it can change at run-time.

Seems like the same issue Java and Self compilers have
when new classes are loaded.

There are Java compilers that optimize method calls by
inlining them, and then "dynamically deoptimize" those
if a derived class that changes the meaning of that
inlined code is loaded.

This is not directly what I'm talking about, but related. You
aren't changing already defined classes (or the class of an
object) in this case. A derived class is overriding a method
definition of a parent - not changing the parent.

In Ruby, I think this would apply to Object and Kernel methods.
In Java, you statically type variables to a given class (or
any class derived from that one). You could inline the method
of the parent class, but if a derived class uses overrides that
method, you'd have to "deoptimize" as you say.

In Ruby, all variables are just an Object, so I think only
methods in Object and Kernel apply to this topic. For some
methods, I don't see why you'd want to override methods in
Object. Take for example Object#equal. If this wasn't
overridable, you could replace every call to equal with a
simple pointer comparison - bypassing method lookup and the
call overhead. I guess you'd need some "final" concept for a
method.

Here's one paper on such dynamic de-optimization:
  

http://research.sun.com/self/papers/dynamic-deoptimization.html

Isn't the real challenge your hypothetical "could recognize
that i is always a Fixnum" condition. If the ruby compiler
could do this, couldn't that same logic recognise that it is
always a pristine, unmodified Fixnum. Knowing the type
sounds
to me like the hard part of the problem. IIRC Lisp added
optional type declarations to the language that you can
use inside performance critical areas like tight-loops.

Yes, this is a hard problem. I'm not sure how much of the time
you could detect the exact class. To really take advantage of
this the compiler would need to unroll the method calls such
that each time a method is called with a different set of
classes for the arguments, you'd compile a new copy of that
method just for those classes.

Even after you figure out how to do this, you still won't be
able to determine whether Fixnum is "pristine" at compile-time,
because the methods of Fixnum can change at run-time.

···

--- Ron M <rm_rails@cheapcomplexdevices.com> wrote:

____________________________________________________
Start your day with Yahoo! - make it your home page

(David A. Black) #17

Hi --

Take a look at the original definition of duck-typing given

by

Dave Thomas. Here is the example he gave:

> When I write
>
> fred << "dog"
>
> in Ruby, I don't care whether fred is a String, a File,

or an

> Array

In this context, the "duck type" of fred is something that
reponds to <<(aString).

By your definition of "type" being "the sum of all of its
capabilities", you'd have to pick what "type" fred is -
String-like, File-like, or Array-like.

On the contrary: I *don't* have to pick or describe or find
synonyms for what it is. That's the point: the type is what's
there. I don't even have to name it.

From what you said above, I don't see any debate over how I
defined "duck type" (other than the name). I only see you
clarifying what you meant by "type". I still don't see a
concrete definition of yours, but it sounds like you might mean
the same as what I said for "duck type". But, when you say
"type" is "the sum of all of its capabilities" and "an
object's type can change and evolve during runtime" this says
to me your "type" is associated with the object itself and not
how the object is used. All that really matters regarding
"type" in my opinion is how an object is used. What a
particular object's entire capabilities and the fact that they
can change over time is orthongonal.

It sounds like you think I mean you should send all possible messages
to an object simultaneously, or something bizarre like that.
Obviously any given use of an object does not recapitulate or
encapsulate its entire type, if "type" is defined as the object's
capabilities. At the same time, it's not a good idea to use an object
in ways its type does not support -- so in that sense, type and how an
object is used are very tightly connected. (Unless you're depending
heavily on method_missing, of course.)

I'm not sure why you don't like the term "duck type". It is
directly associated with the term "duck typing" and is quite
clear in that context. I don't understand the need to talk
about/document an abstract "type" beyond the context of "duck
typing". Can you think of anything else?

I don't like the term "duck type" partly because I consider "type" to
be adequate (since type in Ruby is already a matter of dynamic
message-recognition capabilities, rather than class membership), and
partly because I think the word "duck" sometimes gets used so much and
spread so thin, as a kind of general code-word for anything connected
with dynamic typing, that the original sense of "duck typing" gets
diluted and obscured, which I think is too bad.

I personally wouldn't say "anything IO-like" (nor "O-like", though
that might be closer :slight_smile: but rather: anything that responds to
"write". That's *all* that matters. "IO-like" is a secondary
concept, built on top of that. Let's say someone said: "no, it's
not IO-like; I reject that." That person could still send "write"
to fred, as much as you can.

My point was that if you document your method to take an
IO-like object (which I thought was your way - sum of the
capabilities of an object), you have the freedom to use any of
the IO methods.

I think I may see the problem here: perhaps you think I meant "summary
of the capabilities of an object"? I can't think how else these
notions like "IO-like object" have crept into the discussion. You
seem to think I meant I want to slap specific, sort of pseudo-type
labels on objects (IO-like, String-like, etc.), when what I've been
trying to say is more or less the opposite of that -- namely, that the
"type" of a Ruby object really cannot be labeled or summarized in this
kind of way, because it is only defined by what it actually is at a
given moment.

In fact, the tautology of type renders it close to useless as a
concept in Ruby; but in a pleasant way, I find.

If initially the method is implemented using
<<, it may work with anything that has the << method now, but
you run the risk of something breaking if the implementation
changes to use different or additional methods. If you
document a method like this, you give the method implementation
freedom to use a wide range of methods, but limit the caller to
objects that implement that entire interface.

Why wouldn't you just say: "the argument to this method has to respond
to <<" ?

Of course that is not the duck-typing or ruby way. The
duck-typing way is to document what capabilities you want/need
from an argument and that's it. This gives more freedom to the
caller and less to the method implementation.

I would just call it "documenting a method" :slight_smile: But I'm not the duck
police; you can use it any way you see fit. Certainly documenting the
capabilities you need from an argument sounds like a good way to go
about documentation. Objects whose type comports with the stated
needs can then be used as arguments to that method.

David

···

On Thu, 18 Aug 2005, Eric Mahurin wrote:

--
David A. Black
dblack@wobblini.net

(Eric Mahurin) #18

Ah, the joys of discussing typing in Ruby... at least neither
of us is on the side of wanting static types in Ruby.

>>> Take a look at the original definition of duck-typing
given
>> by
>>> Dave Thomas. Here is the example he gave:
>>>
>>> > When I write
>>> >
>>> > fred << "dog"
>>> >
>>> > in Ruby, I don't care whether fred is a String, a File,
>> or an
>>>
>>> > Array
>>>
>>> In this context, the "duck type" of fred is something
that
>>> reponds to <<(aString).
>>>
>>> By your definition of "type" being "the sum of all of its
>>> capabilities", you'd have to pick what "type" fred is -
>>> String-like, File-like, or Array-like.
>>
>> On the contrary: I *don't* have to pick or describe or
find
>> synonyms for what it is. That's the point: the type is
what's
>> there. I don't even have to name it.
>
> From what you said above, I don't see any debate over how I
> defined "duck type" (other than the name). I only see you
> clarifying what you meant by "type". I still don't see a
> concrete definition of yours, but it sounds like you might
mean
> the same as what I said for "duck type". But, when you say
> "type" is "the sum of all of its capabilities" and "an
> object's type can change and evolve during runtime" this
says
> to me your "type" is associated with the object itself and
not
> how the object is used. All that really matters regarding
> "type" in my opinion is how an object is used. What a
> particular object's entire capabilities and the fact that
they
> can change over time is orthongonal.

It sounds like you think I mean you should send all possible
messages
to an object simultaneously, or something bizarre like that.

No, I'm only talking about how to describe a particular type
(most likely in documentation). I think you and I both agree
that in normal circumstances, one's ruby code should not do any
checking of the type - however you define it (kind_of?,
responds_to?, etc). Otherwise you'd be "caring" about the type
which goes against duck-typing.

Obviously any given use of an object does not recapitulate or
encapsulate its entire type, if "type" is defined as the
object's
capabilities.

And that is why I think this definition of "type" is not very
useful. The definition I gave for duck-type is quite useful in
the context of duck-typing - for documenting arguments of
methods.

...

> I'm not sure why you don't like the term "duck type". It
is
> directly associated with the term "duck typing" and is
quite
> clear in that context. I don't understand the need to talk
> about/document an abstract "type" beyond the context of
"duck
> typing". Can you think of anything else?

I don't like the term "duck type" partly because I consider
"type" to
be adequate (since type in Ruby is already a matter of
dynamic
message-recognition capabilities, rather than class
membership), and
partly because I think the word "duck" sometimes gets used so
much and
spread so thin, as a kind of general code-word for anything
connected
with dynamic typing, that the original sense of "duck typing"
gets
diluted and obscured, which I think is too bad.

I'm not diluting duck-typing at all. In static typing
languages, you associate a specific static type with an
argument. This tells the caller what kinds of oubjects it can
use there. When doing duck-typing within a method, you
describe the duck-type of each argument in the dcumentation.
There is no direct code to describe them, but the caller needs
to know at least from documentation.

>> I personally wouldn't say "anything IO-like" (nor
"O-like", though
>> that might be closer :slight_smile: but rather: anything that
responds to
>> "write". That's *all* that matters. "IO-like" is a
secondary
>> concept, built on top of that. Let's say someone said:
"no, it's
>> not IO-like; I reject that." That person could still send
"write"
>> to fred, as much as you can.
>
> My point was that if you document your method to take an
> IO-like object (which I thought was your way - sum of the
> capabilities of an object), you have the freedom to use any
of
> the IO methods.

I think I may see the problem here: perhaps you think I meant
"summary
of the capabilities of an object"? I can't think how else
these
notions like "IO-like object" have crept into the discussion.
You
seem to think I meant I want to slap specific, sort of
pseudo-type
labels on objects (IO-like, String-like, etc.), when what
I've been
trying to say is more or less the opposite of that -- namely,
that the
"type" of a Ruby object really cannot be labeled or
summarized in this
kind of way, because it is only defined by what it actually
is at a
given moment.

In fact, the tautology of type renders it close to useless as
a
concept in Ruby; but in a pleasant way, I find.

So you do see this definition of type being useless :slight_smile: I think
we are on the same page - mostly.

> If initially the method is implemented using
> <<, it may work with anything that has the << method now,
but
> you run the risk of something breaking if the
implementation
> changes to use different or additional methods. If you
> document a method like this, you give the method
implementation
> freedom to use a wide range of methods, but limit the
caller to
> objects that implement that entire interface.

Why wouldn't you just say: "the argument to this method has
to respond
to <<" ?

Yes, that would be the best (duck-typing) way to do it. I was
just giving a counter-argument as to why you might "require" an
argument to conform to an entire "interface" (or your "useless"
definition of "type") - method implementation freedom. I think
the method caller freedom is more important.

> Of course that is not the duck-typing or ruby way. The
> duck-typing way is to document what capabilities you
want/need
> from an argument and that's it. This gives more freedom to
the
> caller and less to the method implementation.

I would just call it "documenting a method" :slight_smile:

And I'd call it describing the duck-type of an argument just
like one would declare the static-type of an argument in a
statically typed language. If a method doesn't do duck-typing
and instead checks for a class, you'd give that class in the
doc instead of describing a duck-type. Or if the method did
different things based on the objects capabilities/class you'd
be describing something else - not a single duck-type.
Describing a duck-type goes with duck-typing.

···

--- "David A. Black" <dblack@wobblini.net> wrote:

On Thu, 18 Aug 2005, Eric Mahurin wrote:

But I'm not
the duck
police; you can use it any way you see fit. Certainly
documenting the
capabilities you need from an argument sounds like a good way
to go
about documentation. Objects whose type comports with the
stated
needs can then be used as arguments to that method.

David

--
David A. Black
dblack@wobblini.net

__________________________________
Yahoo! Mail for Mobile
Take Yahoo! Mail with you! Check email on your mobile phone.
http://mobile.yahoo.com/learn/mail

(David A. Black) #19

Hi --

It sounds like you think I mean you should send all possible
messages to an object simultaneously, or something bizarre like
that.

No, I'm only talking about how to describe a particular type
(most likely in documentation). I think you and I both agree
that in normal circumstances, one's ruby code should not do any
checking of the type - however you define it (kind_of?,
responds_to?, etc). Otherwise you'd be "caring" about the type
which goes against duck-typing.

I think of respond_to? as a kind of "weak duck typing" :slight_smile:

Obviously any given use of an object does not recapitulate or
encapsulate its entire type, if "type" is defined as the object's
capabilities.

And that is why I think this definition of "type" is not very
useful. The definition I gave for duck-type is quite useful in
the context of duck-typing - for documenting arguments of
methods.

I'm not sure how we've gotten onto documentation. (Yes, I know it's
all part of programming responsibily....) Anyway, if you want to
say: "This method takes an argument whose duck type is 'this object
responds to "x"'", instead of: "This method takes an argument that
responds to 'x'", be my guest :slight_smile: I don't see what it adds. I prefer
the shorter way.

David

···

On Thu, 18 Aug 2005, Eric Mahurin wrote:

--- "David A. Black" <dblack@wobblini.net> wrote:

--
David A. Black
dblack@wobblini.net

(Eric Mahurin) #20

>> Obviously any given use of an object does not recapitulate
or
>> encapsulate its entire type, if "type" is defined as the
object's
>> capabilities.
>
> And that is why I think this definition of "type" is not
very
> useful. The definition I gave for duck-type is quite
useful in
> the context of duck-typing - for documenting arguments of
> methods.

I'm not sure how we've gotten onto documentation. (Yes, I
know it's
all part of programming responsibily....)

In ruby, since you don't declare the type of your arguments
anywhere in the code (like you would in a statically typed
languaage), the only place left to discuss the "type" is in the
documentation. I don't see where else "type" really matters.

Anyway, if you
want to
say: "This method takes an argument whose duck type is 'this
object
responds to "x"'", instead of: "This method takes an argument
that
responds to 'x'", be my guest :slight_smile: I don't see what it adds.
I prefer
the shorter way.

I prefer the shorter way too. There is no reason to use the
words duck, type, or a combination of the two, even though you
are clearly duck-typing. Similarly, when a you declare a
static type to an argument in a statically typed language, you
don't use the words static or type (unless either of those are
needed keywords in the language).

···

--- "David A. Black" <dblack@wobblini.net> wrote:

____________________________________________________
Start your day with Yahoo! - make it your home page