[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

New Type Checking System Idea

Sean O'Dell

11/20/2003 9:09:00 PM

Taking comments into consideration, a totally new approach strikes me
regarding type checking.

As briefly as I can:

What if we had a way to describe a class interface that basically does this:
"from this point forward, any methods added to this class definition will be
checked against an interface description, and any methods whose names matches
a method described in the interface must take the number and type of
parameters described, and the class will be considered incomplete until the
very last method described by the interface is added to the class."

*** Some basic rules about this:

Classes do not *need* an interface. They can go on just the way the are now,
completely open and free. For someone who doesn't like to use interfaces,
they are completely unaffected.

Interfaces are immutable and cannot be extended, but you can subclass other
interfaces from them.

Interfaces have unique, global names based on where they were defined. They
take the name of the class or module they were described in, but they are not
otherwise related to the class or module.

Interfaces can be assigned to any class regardless of its proximity to the
interface description.

Once a class has been assigned an interface, it's an error to change the
number or types of parameters described methods take.

You can still add methods any way you like, so long as they're not part of the
described interface for the class.

When you subclass from a class with an interface, or mix-in a module that has
an interface, the subclass has that interface as well.

You can re-implement methods in a subclass which has inherited an interface,
but the methods must have the same number and types of parameters.

*** Some performance notes:

These checks are only being as the class is assembled, or when it is modified.
I believe this is called at compile-time regarding Ruby. (?)

Once marked complete, objects generated from that class are marked with a
simple flag stating that it adheres to the interface.

*** Syntax sugar

Parameter and return types are interface names.

If a method needs to enforce a parameter type check, objects passed to that
parameter must contain a "complete" flag for the interface required.

*** Chicken-and-the-egg

Build-in interfaces for all the predefined Ruby classes like T_NIL, T_OBJECT,
T_CLASS, T_MODULE, etc.

*** Example of interface declaration

module IO

class Stream
interface
def Boolean eof?
end

class Input < IO::Stream
interface
def Integer read(Integer maxbytes)
end
end
end

end

*** Example of class definition using an interface

class Stdin
implements IO::Stream::Input
# interface is incompletely fulfilled here

def Boolean eof?
return is-at-end-of-file
end # ==> implemented correctly, but class is still partially incomplete


def Integer read(Integer maxbytes)
return bytes-read
end # ==> class is now marked complete

def someothermethod
end # ==> perfectly ok too

end

*** Example of re-implementing class methods

class Stdin
def Integer read(Integer maxbytes)
return do-something-completely-different-and-return
end
# ==> allowed because it matches the interface description
# for this method
end

*** Example of re-implementing object methods

class <<$stdin
def Integer read(Integer maxbytes)
return do-something-completely-different-and-return
end
# ==> also allowed because it matches the interface
# description for this method
end

*** Summary

1) It doesn't affect existing classes
2) It can be ignored by people who don't want it
3) Performance hit at runtime is merely a very short interface table lookup
4) Integrity of the type checking is high

Anything wrong with this way of doing it?

Sean O'Dell



15 Answers

T. Onoma

11/20/2003 11:49:00 PM

0

sean could you put this on the garden wiki?

http://www.rubygarden.org/ruby?RiteS...

-t0

On Thursday 20 November 2003 10:08 pm, Sean O'Dell wrote:
> Taking comments into consideration, a totally new approach strikes me
> regarding type checking.
>
> As briefly as I can:
>
> What if we had a way to describe a class interface that basically does
> this: "from this point forward, any methods added to this class definition
> will be checked against an interface description, and any methods whose
> names matches a method described in the interface must take the number and
> type of parameters described, and the class will be considered incomplete
> until the very last method described by the interface is added to the
> class."
>
> *** Some basic rules about this:
>
> Classes do not *need* an interface. They can go on just the way the are
> now, completely open and free. For someone who doesn't like to use
> interfaces, they are completely unaffected.
>
> Interfaces are immutable and cannot be extended, but you can subclass other
> interfaces from them.
>
> Interfaces have unique, global names based on where they were defined.
> They take the name of the class or module they were described in, but they
> are not otherwise related to the class or module.
>
> Interfaces can be assigned to any class regardless of its proximity to the
> interface description.
>
> Once a class has been assigned an interface, it's an error to change the
> number or types of parameters described methods take.
>
> You can still add methods any way you like, so long as they're not part of
> the described interface for the class.
>
> When you subclass from a class with an interface, or mix-in a module that
> has an interface, the subclass has that interface as well.
>
> You can re-implement methods in a subclass which has inherited an
> interface, but the methods must have the same number and types of
> parameters.
>
> *** Some performance notes:
>
> These checks are only being as the class is assembled, or when it is
> modified. I believe this is called at compile-time regarding Ruby. (?)
>
> Once marked complete, objects generated from that class are marked with a
> simple flag stating that it adheres to the interface.
>
> *** Syntax sugar
>
> Parameter and return types are interface names.
>
> If a method needs to enforce a parameter type check, objects passed to that
> parameter must contain a "complete" flag for the interface required.
>
> *** Chicken-and-the-egg
>
> Build-in interfaces for all the predefined Ruby classes like T_NIL,
> T_OBJECT, T_CLASS, T_MODULE, etc.
>
> *** Example of interface declaration
>
> module IO
>
> class Stream
> interface
> def Boolean eof?
> end
>
> class Input < IO::Stream
> interface
> def Integer read(Integer maxbytes)
> end
> end
> end
>
> end
>
> *** Example of class definition using an interface
>
> class Stdin
> implements IO::Stream::Input
> # interface is incompletely fulfilled here
>
> def Boolean eof?
> return is-at-end-of-file
> end # ==> implemented correctly, but class is still partially incomplete
>
>
> def Integer read(Integer maxbytes)
> return bytes-read
> end # ==> class is now marked complete
>
> def someothermethod
> end # ==> perfectly ok too
>
> end
>
> *** Example of re-implementing class methods
>
> class Stdin
> def Integer read(Integer maxbytes)
> return do-something-completely-different-and-return
> end
> # ==> allowed because it matches the interface description
> # for this method
> end
>
> *** Example of re-implementing object methods
>
> class <<$stdin
> def Integer read(Integer maxbytes)
> return do-something-completely-different-and-return
> end
> # ==> also allowed because it matches the interface
> # description for this method
> end
>
> *** Summary
>
> 1) It doesn't affect existing classes
> 2) It can be ignored by people who don't want it
> 3) Performance hit at runtime is merely a very short interface table
> lookup 4) Integrity of the type checking is high
>
> Anything wrong with this way of doing it?
>
> Sean O'Dell



Greg McIntyre

11/21/2003 12:34:00 AM

0

I like your idea, Sean, but it's too much effort! If it is onerous then
it won't be used. Perhaps if we based it upon method name and arity
(essentially replacing a bunch of respond_to?() calls with arity
checks added in as a bonus). This is because it requires no extra effort
on the programmer's part, so it fits into the existing Ruby syntax.

I took your code and rewrote it a bit...


class IO
class Stream
def eof?
# ...
end
end

# Class IO::Stream defined. Interface IO::Stream defined:
# [[eof?,0]]

class InputStream < IO::Stream
def read(maxbytes)
# ...
end
end

# Class IO::InputStream defined. Interface IO::InputStream
# defined: [[eof?,0], [read,1]]
end

# Class IO defined. Interface IO defined: []


### Example of class definition using an interface

class Stdin
implements IO::InputStream

# Interface: []
# Needed: [[eof?,0], [read,1]]

def eof?
# ...
end

# Interface: [[eof?,0]]
# Needed: [[eof?,0], [read,1]]

def read(maxbytes)
# ...
end

# Interface: [[eof?,0], [read,1]]
# Needed: [[eof?,0], [read,1]]

def someothermethod
end

# Interface: [[eof?,0], [read,1], [someothermethod,0]]
# Needed: [[eof?,0], [read,1]]

end # RUN-TIME CHECK: Promises fulfilled. Interface Stdin produced.


### Example of re-implementing class methods

class Stdin
def read(maxbytes=20)
# do something different
end

# Interface: [[eof?,0], [read,-1], [someothermethod,0]]
# Needed: [[eof?,0], [read,1]]

end # RUN-TIME CHECK: Promises fulfilled. Interface Stdin kept.
# => Warning, default value for maxbytes in method read may
# never be used by interface(?)
# => No warning, interface made more general(?)


### Example of breaking class interface

class Stdin
def read(maxbytes, retries)
# do something different
end

# Interface: [[eof?,0], [read,2], [someothermethod,0]]
# Needed: [[eof?,0], [read,1]]

end # RUN-TIME CHECK: Promises broken. Interface Stdin deleted.
# => Raise type error(?)


### Example of re-implementing object methods

class << $stdin
def read(maxbytes)
# do something different again
end

# Interface: [[eof?,0], [read,1], [someothermethod,0]]
# Needed: [[eof?,0], [read,1]]

end # RUN-TIME CHECK: Interface fulfilled. No action taken.


--
Greg McIntyre ======[ greg@puyo.cjb.net ]===[ http://pu... ]===

Sean O'Dell

11/21/2003 12:54:00 AM

0

On Thursday 20 November 2003 04:37 pm, Greg McIntyre wrote:
> I like your idea, Sean, but it's too much effort! If it is onerous then
> it won't be used. Perhaps if we based it upon method name and arity
> (essentially replacing a bunch of respond_to?() calls with arity
> checks added in as a bonus). This is because it requires no extra effort
> on the programmer's part, so it fits into the existing Ruby syntax.

Very funny. =)

Actually, I sort of meant my proposal to require a very minimal effort for
both sides. On Matz' end (save for syntax sugar) it's not a heck of a lot to
code, and it doesn't screech hard against the existing code (at least not
from what I've seen, could be wrong), and on our side it's just a short block
of interface description to write. It really couldn't get a heck of a lot
easier except to just not do it, or to do some sort of interface id tagging
thing like my first proposal, where no enforcement was performed at all.

> I took your code and rewrote it a bit...

Ha. Ha. =)

It looks like too much happens at run-time, always checking and querying for
certain methods, etc. Also, the concept of a whole interface, rather than
querying for a set of required methods, I always think is easier to grasp.

I mean, there will always be respond_to? and for those people who see no use
in interface checking, they can, as always, keep just asking respond_to? or
not asking anything at all. Your changes seemed to be sort of a souped-up
respond_to? engine.

Not to mention, no information about required parameter types.

My feeling is, a short run of overhead at compile-time is better than constant
overhead at run-time. My proposal does all the interface fulfillment
checking at compile-time, then conformance checks are done with a simple flag
test internally.

Sean O'Dell



Geoff Youngs

11/21/2003 1:35:00 AM

0

On Fri, Nov 21, 2003 at 06:08:39AM +0900, Sean O'Dell wrote:
> Taking comments into consideration, a totally new approach strikes me
> regarding type checking.

> As briefly as I can:

> What if we had a way to describe a class interface that basically does
> this: "from this point forward, any methods added to this class
> definition will be checked against an interface description, and any
> methods whose names matches a method described in the interface must
> take the number and type of parameters described, and the class will
> be considered incomplete until the very last method described by the
> interface is added to the class."

> *** Some basic rules about this:

> Classes do not *need* an interface. They can go on just the way the
> are now, completely open and free. For someone who doesn't like to
> use interfaces, they are completely unaffected.

> Interfaces are immutable and cannot be extended, but you can subclass
> other interfaces from them.

Why? Is there any reason that interfaces shouldn't be as mutable as
classes and/or modules are?

I've played with a soft interface implementation which works reasonably
well where I've used it, but it's worth considering existing ruby usage.
And the most common example I come across of a Ruby interface is
Enumerable.

The problems (as I see it) with the current implementation of Enumerable
are that:

1/ It doesn't check for the existance of 'each' until you call a
method.
2/ It has brute force methods which could be implemented more
efficiently in specialised collections, e.g. Range, or a sorted
array.
3/ It supports reflection poorly. ie. there's no easy way to look at
Enumerable and work out what a class needs as a pre-requisite
in order to use Enumerable usefully.

1/ Could be solved using Iface.append_features(aClassOrModule) to check
that the class defines 'each' as an instance method.
3/ Could be solved by making the interface keep track of the required
methods (which would help generically solve 1)
2/ Could be solved by allowing the interface to provide methods which
don't override class methods of the same name.

There are also non-functional interfaces:
e.g. Marshal requires _dump and class._load to be defined.

The advantage of using a specified interface is that duck-typing isn't
enough. And as language doesn't have a infinite list of suitable
methods names, there's the chance that there may well be a clash.

e.g.

class AmericanClothes
attr_reader :pants
end

class BritishPerson
def put_on_underwear(clothesSource)
if @underwear.nil?
if clothesSources.respond_to?(:pants)
put_on(clothesSource.pants)
else
raise ClothingError, "No suitable underwear"
end
end
end
end

Which is a tongue in cheek example, but the point is that there is no
universal atomic source of method names.

But an interface could exist in a global namespace, and thus guarantee
(as much as anything does in Ruby at the moment) that method :x does
what is expected of it, because the class declares it's conformance.

Another reason for a clear interface definitions which I haven't
noticed being mentioned is that for some purposes libraries need types
which are more complex than Ruby's simple builtin types. The library
will either need a large number of respond_to? calls or a simple "does
it claim to conform to interface X?". The advantages of interfaces as
proposed are twofold - for the programmer a clear definition of the
expectations as regard a complex object, for the library a simple check
for conformance. And regardless of what some detractors have said, I do
believe that this adds rather than detracts from the dynamism of Ruby -
so much Ruby code checks for kind_of?(IO) when it really means
implements?(IORead). With interfaces this could and should be clearer
and promote better programming practices.

> Interfaces have unique, global names based on where they were defined.
> They take the name of the class or module they were described in, but
> they are not otherwise related to the class or module.

Aren't/Couldn't they be a specialised module?

> Interfaces can be assigned to any class regardless of its proximity to
> the interface description.

> Once a class has been assigned an interface, it's an error to change
> the number or types of parameters described methods take.

Isn't this an unlikely contingency to cater for? And more trouble than
it's worth?

If there's a library with an interface which accepts string arguments to
a particular methods, for example.

--- in foo.rb
interface Foo
def bar(String title)
end

--- in myprog.rb
class Bob
implements Foo
def bar(String|IORead title)
...
end
end

Couldn't the programmer end up in the situation where they have to
modify a library (and either hope that the change is accepted by the
library author or distribute a modified version of the library) so that
they can have a class which behaves as they wish when used by their
code, but which is also accepted by the library?

With dynamic interface definitions this sort of thing could be worked
around, but if they were immutable then every application author would
have to rely on every interface using library author anticipating all
possible uses of their library.

> You can still add methods any way you like, so long as they're not
> part of the described interface for the class.

See above.

> When you subclass from a class with an interface, or mix-in a module
> that has an interface, the subclass has that interface as well.

This is pretty much essential, but you'd get it "for free" if interfaces
were specialised modules.

> You can re-implement methods in a subclass which has inherited an
> interface, but the methods must have the same number and types of
> parameters.

Ok - but I still don't see why a program that knows what it's doing
can't take a class and use alias_method to insert hooks in a particular
function.

> *** Syntax sugar

> Parameter and return types are interface names.

> If a method needs to enforce a parameter type check, objects passed to
> that parameter must contain a "complete" flag for the interface
> required.

Nice, but automated parameter type checking is not essential for a basic
interface implementation.

[snip]

> Anything wrong with this way of doing it?

The main disadvantages I see are as follows:
1/ Compatibility
Libraries using this will not be usable earlier versions of
Ruby. As in they will break completely or displayed undefined
behaviour - this is a Bad Thing(TM) and will damage uptake.
(The great thing about so many of the changes between 1.6 and
1.8 is that many of them can be utilised but 1.6 still supported
by means of a compatibility layer written in Ruby - (I, for
example, still have a machine running 1.6 which I'm not in a
position to upgrade at the moment - hence pretty much anything
I write in Ruby for work needs to run on both).
2/ Dynamic extensibillity
I have a big problem with making interfaces immutable - it just
doesn't feel right in Ruby. And greater certainty that the
object isn't lying seems to be the only reason given for doing
it. (Ignoring the fact that the Object could be lie about the
return value of kind_of? anyway)
3/ Core interpreter
There are already various "core" features implemented in pure
Ruby - the most prominent being the Singleton mix-in. I don't
see evidence supporting the notion that unless it's done in
Ruby's C source, interfaces won't/can't become a meaningful and
useful tool - I would agree though that they are unlikely to
have significant penetration unless an implementation is chosen
and included in the core distribution.

Hope this is of interest,


Geoff.



Greg McIntyre

11/21/2003 2:05:00 AM

0

"Sean O'Dell" <sean@celsoft.com> wrote:
> On Thursday 20 November 2003 04:37 pm, Greg McIntyre wrote:
> > I like your idea, Sean, but it's too much effort! If it is onerous
> > then it won't be used. Perhaps if we based it upon method name and
> > arity(essentially replacing a bunch of respond_to?() calls with
> > arity checks added in as a bonus). This is because it requires no
> > extra effort on the programmer's part, so it fits into the existing
> > Ruby syntax.
>
> Very funny. =)

Gee, I wasn't trying to be funny. I really would be annoyed if I had to
write as much as you did to have interfaces. A lot of what you would
end up writing would be repeditive, in the same way that with C++,
writing .h and.cpp files repeats a lot of information (i.e. the type
signatures).


> Actually, I sort of meant my proposal to require a very minimal effort
> for both sides. On Matz' end (save for syntax sugar) it's not a heck
> of a lot to code, and it doesn't screech hard against the existing
> code (at least not from what I've seen, could be wrong), and on our
> side it's just a short block of interface description to write. It
> really couldn't get a heck of a lot easier except to just not do it,
> or to do some sort of interface id tagging thing like my first
> proposal, where no enforcement was performed at all.

The main problem I see, with both versions, is that they put the onus on
the class provider to define all supported interfaces, whereas use of
respond_to? puts the onus on the class client to assert the object
supports the minimally required interface. Where _should_ the
responsibility be? If it's up to the provider then the client may end up
with an object which does not promise to support an interface it could
because it is ignorant of it: i.e. it may restrict duck typing. If it's
up to the class consumer then all that checking becomes a pain (and
inefficient). Hmm...

Can you clarify your idea in the following regard?

Can I check one object against another's interface at run-time if I
desire it?

def read_from(object)
if object.complies(IO::InputStream.interface)
# ...
end
end


> > I took your code and rewrote it a bit...
>
> Ha. Ha. =)
>
> It looks like too much happens at run-time, always checking and
> querying for certain methods, etc.

At "definition" time, yes (when the class is defined). Isn't that what
your code does? Ruby has no "compile" time, after all...


> Also, the concept of a whole
> interface, rather than querying for a set of required methods, I
> always think is easier to grasp.

Yes, I'm all for grouping these queries into identifiable interfaces. I
think that's a Good Thing.


> I mean, there will always be respond_to? and for those people who see
> no use in interface checking, they can, as always, keep just asking
> respond_to? or not asking anything at all. Your changes seemed to be
> sort of a souped-up respond_to? engine.

Yes, that's a good way to describe it... which is interface checking. :)
It's just that the interface contains a little less information than the
type signatures of statically typed languages.

In practice (and we've had a decade of it), Guido and matz have shown us
that we don't really need such strong type safety -- it's a frictional
force while programming and the difference it makes in practice is
minimal.


> Not to mention, no information about required parameter types.

Exactly, that's what it leaves out. Then you could, optionally, ask Ruby
whether object X fulfils interface Y and it would tell you without any
respond_to? action. It's like... precalculated respond_to? :-) I think
it could work because of inheritance (wow, it comes in handy after all)
-- more general classes like IO::Stream can define fewer or more
abstract methods and create abstract interfaces *at the same time*
without the effort of defining the interface explicitly, separately.

You'd probably want to allow explicit interface definitions too, I just
think you're creating more work for yourself if you ingore what you
already have...


> My feeling is, a short run of overhead at compile-time is better than
> constant overhead at run-time.

I agree, except yoursentence.gsub!(/compile/, 'definition'), or whatever
the more accepted term is for that stage of execution.


> My proposal does all the interface fulfillment checking at
> compile-time, then conformance checks are done with a simple flag test
> internally.

I thought my suggestion would too. It's based closely upon your
suggestion after all... I just "Rubied" the information you keep in your
interface so it did not tread on the pretty ducks. ;)

--
Greg McIntyre ======[ greg@puyo.cjb.net ]===[ http://pu... ]===

Greg McIntyre

11/21/2003 2:12:00 AM

0

Geoff Youngs <g@intersect-uk.co.uk> wrote:
> I've played with a soft interface implementation which works
> reasonably well where I've used it...

Oooh, how does it work?

I tried redefining Module#append_features to call a hook which can be
defined to check for the methods the module needs. The only drawback is
you have to include your modules down the bottom of the class. It
doesn't work for inheritance however because Class::inherited is called
at the start of a class definition, not at the end.

So far that's the best Ruby 1 patch-up job I can do to get, as you put
it, soft interface checking. That is, the best without introducing a lot
more ugly code...

--
Greg McIntyre ======[ greg@puyo.cjb.net ]===[ http://pu... ]===

Sean O'Dell

11/21/2003 2:59:00 AM

0

On Thursday 20 November 2003 06:07 pm, Greg McIntyre wrote:
> "Sean O'Dell" <sean@celsoft.com> wrote:
> > On Thursday 20 November 2003 04:37 pm, Greg McIntyre wrote:
> > > I like your idea, Sean, but it's too much effort! If it is onerous
> > > then it won't be used. Perhaps if we based it upon method name and
> > > arity(essentially replacing a bunch of respond_to?() calls with
> > > arity checks added in as a bonus). This is because it requires no
> > > extra effort on the programmer's part, so it fits into the existing
> > > Ruby syntax.
> >
> > Very funny. =)
>
> Gee, I wasn't trying to be funny. I really would be annoyed if I had to
> write as much as you did to have interfaces. A lot of what you would
> end up writing would be repeditive, in the same way that with C++,
> writing .h and.cpp files repeats a lot of information (i.e. the type
> signatures).

Oh, you didn't mean it? Oops ... I saw a close resemblance between your code
and something someone else proposed, and your suggestions were so far from my
proposal, I thought you were ribbing me!

Anyway, how little can you write to describe an interface? I mean, somewhere
you have to write it out. It can't be avoided. Someone has to put the
requirement down in type somewhere. If it's not the interface designer, then
the developers have to ask for their requirements. I think the least amount
of typing is a situation where the interface designer types it out once,
gives it a name, and developers just refer to it by name thereafter.

> > Actually, I sort of meant my proposal to require a very minimal effort
> > for both sides. On Matz' end (save for syntax sugar) it's not a heck
> > of a lot to code, and it doesn't screech hard against the existing
> > code (at least not from what I've seen, could be wrong), and on our
> > side it's just a short block of interface description to write. It
> > really couldn't get a heck of a lot easier except to just not do it,
> > or to do some sort of interface id tagging thing like my first
> > proposal, where no enforcement was performed at all.
>
> The main problem I see, with both versions, is that they put the onus on
> the class provider to define all supported interfaces, whereas use of
> respond_to? puts the onus on the class client to assert the object
> supports the minimally required interface. Where _should_ the
> responsibility be? If it's up to the provider then the client may end up
> with an object which does not promise to support an interface it could
> because it is ignorant of it: i.e. it may restrict duck typing. If it's
> up to the class consumer then all that checking becomes a pain (and
> inefficient). Hmm...

I think when you are talking about interfaces, you are describing a contract,
and that goes to the interface designer.

> Can you clarify your idea in the following regard?
>
> Can I check one object against another's interface at run-time if I
> desire it?
>
> def read_from(object)
> if object.complies(IO::InputStream.interface)
> # ...
> end
> end

Yes, if you didn't use syntax sugar to tell Ruby to please enforce that object
completely fulfilled the IO::InputStream interface, you could ask
object.implements?(IO::InputStream) (which is how I think my proposal worded
it, but yours is equivalent).

> At "definition" time, yes (when the class is defined). Isn't that what
> your code does? Ruby has no "compile" time, after all...

Yes, that's when I mean.

> > I mean, there will always be respond_to? and for those people who see
> > no use in interface checking, they can, as always, keep just asking
> > respond_to? or not asking anything at all. Your changes seemed to be
> > sort of a souped-up respond_to? engine.
>
> Yes, that's a good way to describe it... which is interface checking. :)
> It's just that the interface contains a little less information than the
> type signatures of statically typed languages.

Yes, my proposal did not say anything about the end developer any way to ask
about the types required. But if Matz does the internals for interface
checking, he can also add methods to the Method class to do that sort of
thing. Internally, he's going to have to come up with some way to encode
method names, parameter numbers and interface requirements into an nifty,
easy-to-use internal structure. The information in that structure can be
exported back to Ruby in any number of ways. I think it comes with the
territory eventually. I think discussions about that would be down the line,
and lots of nifty ideas could surface.

> In practice (and we've had a decade of it), Guido and matz have shown us
> that we don't really need such strong type safety -- it's a frictional
> force while programming and the difference it makes in practice is
> minimal.

People have their reasons for wanting it, though, as do I. I think there are
a myriad of reasons they would be good, and I can list them all, and others
can add to the list, but ultimately those reasons can be argued down. I
don't think any way to do anything is imminently set in stone; almost
everything has a work around.

> You'd probably want to allow explicit interface definitions too, I just
> think you're creating more work for yourself if you ingore what you
> already have...

I think the problem is partially that we don't have enough type information to
try anything with, just to see, so we need something to start down that path.
Once it's there, we can see where else such information would be useful.

Ultimately, though, I think interfaces will be their most important use. Some
people will still do things by querying one method at a time, getting a
little more information than they were before.

> > My proposal does all the interface fulfillment checking at
> > compile-time, then conformance checks are done with a simple flag test
> > internally.
>
> I thought my suggestion would too. It's based closely upon your
> suggestion after all... I just "Rubied" the information you keep in your
> interface so it did not tread on the pretty ducks. ;)

In your modification, you were building these arrays every time, and then for
conformance, I assume Ruby would have to do an array-to-array comparison to
determine compliance. It's sort of the same thing, but since that would
happen constantly at run-time, I think it's probably more overhead than we're
aiming for. But yeah, it's definitely the same thing.

Though, of course, the method information could be reported in a similar way.
I guess we'd have to look at the interface implementation to tell what we can
and can't report back.

Sean O'Dell



Greg McIntyre

11/21/2003 3:25:00 AM

0

"Sean O'Dell" <sean@celsoft.com> wrote:
> In your modification, you were building these arrays every time, and
> then for conformance, I assume Ruby would have to do an array-to-array
> comparison to determine compliance. It's sort of the same thing, but
> since that would happen constantly at run-time, I think it's probably
> more overhead than we're aiming for. But yeah, it's definitely the
> same thing.

Ah, that wasn't clear in my email. Ruby must do something like that
already because at any stage you can get a list of a classes's public
instance methods. I was just putting it in a comment for clarity. There
were no checks between the methods, just at the end of the class
definition (or partial class definition, if it spans multiple files), to
assert whether or not what's there so far implements the promised
interfaces.

I think that's necessary though because it can't build a list of
required methods at the start based upon the interfaces promised and
then slowly destroy it, then check it's empty at the end, because the
list of "unfulfilled methods" may grow again and I don't see how that
would happen if you destroyed the list of interface methods needed...

And just to clarify, what I meant by "too much work" was that when you
define a class, you implicity define its interface (although this
interface in Ruby 1 only has method names and arities), so I wouldn't
want to have to define a class's interface separately in order to say
"ensure this object implements this _class's_ interface".

So it's like your proposal, only with an implicit shortcut. You could
either define interfaces by defining classes and referring to their
interfaces (in that respect a Class object "has" an Interface object),
or define standalone interfaces unrelated to classes and assert
that objects implement them at run-time, or include them in classes to
prevent forgetfulness when implementing (see Enumerable's problem with
#each). :-)

I think that's what you meant, I just wanted to be clear about it.

However I'm still thinking about what Geoff Youngs suggested about
uniquely identifying the purpose of components in an interface. With
fine-grained respond_to? checking, you wouldn't know what :pants really
was for, it could mean several things. Whereas if this were part of an
interface, would that interface provide enough context to identify its
purpose? Is it possible to uniquely identify a method's purpose given
its context in a well-written set of interfaces? My brain's fizzled and
I need time to think about it. It's probably not perfect but it's
good, I think. :-)

--
Greg McIntyre ======[ greg@puyo.cjb.net ]===[ http://pu... ]===

Sean O'Dell

11/21/2003 3:51:00 AM

0

On Thursday 20 November 2003 07:27 pm, Greg McIntyre wrote:
> "Sean O'Dell" <sean@celsoft.com> wrote:
> > In your modification, you were building these arrays every time, and
> > then for conformance, I assume Ruby would have to do an array-to-array
> > comparison to determine compliance. It's sort of the same thing, but
> > since that would happen constantly at run-time, I think it's probably
> > more overhead than we're aiming for. But yeah, it's definitely the
> > same thing.
>
> Ah, that wasn't clear in my email. Ruby must do something like that
> already because at any stage you can get a list of a classes's public
> instance methods. I was just putting it in a comment for clarity. There
> were no checks between the methods, just at the end of the class
> definition (or partial class definition, if it spans multiple files), to
> assert whether or not what's there so far implements the promised
> interfaces.
>
> I think that's necessary though because it can't build a list of
> required methods at the start based upon the interfaces promised and
> then slowly destroy it, then check it's empty at the end, because the
> list of "unfulfilled methods" may grow again and I don't see how that
> would happen if you destroyed the list of interface methods needed...

Internally, though, Ruby would store the interface information in its own way.
When a class declared that it implements it, as methods are added to the
class which fulfill the interface requirements, they would be checked off
until the last one, then a flag would be raised for the class to indicate
that it fully implements the interface.

It would all be done at class-load-time.

> And just to clarify, what I meant by "too much work" was that when you
> define a class, you implicity define its interface (although this
> interface in Ruby 1 only has method names and arities), so I wouldn't
> want to have to define a class's interface separately in order to say
> "ensure this object implements this _class's_ interface".

No, the definition is written once and then methods refer to the interface by
its name only.

> However I'm still thinking about what Geoff Youngs suggested about
> uniquely identifying the purpose of components in an interface. With
> fine-grained respond_to? checking, you wouldn't know what :pants really
> was for, it could mean several things. Whereas if this were part of an
> interface, would that interface provide enough context to identify its
> purpose? Is it possible to uniquely identify a method's purpose given
> its context in a well-written set of interfaces? My brain's fizzled and
> I need time to think about it. It's probably not perfect but it's
> good, I think. :-)

Interfaces usually imply a purpose, and since an object usually has multiple
methods, all of which do something different, but for one general purpose,
wrapping the purpose up as an interface is convenient.

Sean O'Dell



Greg McIntyre

11/21/2003 4:14:00 AM

0

"Sean O'Dell" <sean@celsoft.com> wrote:
> Internally, though, Ruby would store the interface information in its
> own way. When a class declared that it implements it, as methods are
> added to the class which fulfill the interface requirements, they
> would be checked off until the last one, then a flag would be raised
> for the class to indicate that it fully implements the interface.

I don't think they need to be checked off. Couldn't the "end" which
finishes the class definition (or part-thereof) signal a single check?
It might be a more complex check and hence the same overall efficiency,
or it might be better. *shrug*

I'm trying not to think *too* hard about efficiency. Premature
optimization and all that...


> It would all be done at class-load-time.

Yes.


> > And just to clarify, what I meant by "too much work" was that when
> > you define a class, you implicity define its interface (although
> > this interface in Ruby 1 only has method names and arities), so I
> > wouldn't want to have to define a class's interface separately in
> > order to say"ensure this object implements this _class's_
> > interface".
>
> No, the definition is written once and then methods refer to the
> interface by its name only.

Well, matz in another post says he's against implicit interface
definition through class definitions.

Perhaps an additional line at the end of the class would be a
compromise?

class Foo
# ...
end

interface IFoo from class Foo

Or something. In fact, I could probably do this in Ruby 1 by doing this:

class Foo
# ...

define_interface(:IFoo)
end


> Interfaces usually imply a purpose, and since an object usually has
> multiple methods, all of which do something different, but for one
> general purpose, wrapping the purpose up as an interface is
> convenient.

This is where the use of interfaces really beats, I think, use of
respond_to?. Interfaces provide context.

I think I might have a go at implementing my proposal (or
over-simplification as the case may be) in Ruby 1.8 because it's a
hybrid between Ruby 1 and your proposal. Then I could observe how the
interfaces get broken and fixed with the removal and addition of
methods. :) I can also include an explicit method call to check a set of
parameters implement a set of interfaces, so you'd have optional
parameter type (or rather interface) checking too.

--
Greg McIntyre ======[ greg@puyo.cjb.net ]===[ http://pu... ]===