New Type Checking System Idea

Discussion in 'Ruby' started by Sean O'Dell, Nov 20, 2003.

  1. Sean O'Dell

    Sean O'Dell Guest

    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
     
    Sean O'Dell, Nov 20, 2003
    #1
    1. Advertising

  2. sean could you put this on the garden wiki?

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

    -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
     
    Thomas Sawyer, Nov 20, 2003
    #2
    1. Advertising

  3. 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 ======[ ]===[ http://puyo.cjb.net ]===
     
    Greg McIntyre, Nov 21, 2003
    #3
  4. Sean O'Dell

    Sean O'Dell Guest

    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
     
    Sean O'Dell, Nov 21, 2003
    #4
  5. Sean O'Dell

    Geoff Youngs Guest

    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.
     
    Geoff Youngs, Nov 21, 2003
    #5
  6. "Sean O'Dell" <> 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 ======[ ]===[ http://puyo.cjb.net ]===
     
    Greg McIntyre, Nov 21, 2003
    #6
  7. Geoff Youngs <> 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 ======[ ]===[ http://puyo.cjb.net ]===
     
    Greg McIntyre, Nov 21, 2003
    #7
  8. Sean O'Dell

    Sean O'Dell Guest

    On Thursday 20 November 2003 06:07 pm, Greg McIntyre wrote:
    > "Sean O'Dell" <> 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
     
    Sean O'Dell, Nov 21, 2003
    #8
  9. "Sean O'Dell" <> 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 ======[ ]===[ http://puyo.cjb.net ]===
     
    Greg McIntyre, Nov 21, 2003
    #9
  10. Sean O'Dell

    Sean O'Dell Guest

    On Thursday 20 November 2003 07:27 pm, Greg McIntyre wrote:
    > "Sean O'Dell" <> 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
     
    Sean O'Dell, Nov 21, 2003
    #10
  11. "Sean O'Dell" <> 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 ======[ ]===[ http://puyo.cjb.net ]===
     
    Greg McIntyre, Nov 21, 2003
    #11
  12. Sean O'Dell

    Sean O'Dell Guest

    On Thursday 20 November 2003 08:17 pm, Greg McIntyre wrote:
    > "Sean O'Dell" <> 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*


    Well, code can be called during class loading that might also inject new
    methods. I guess it still could all be saved for one big check at end. I
    think that is definitely a possibility!

    > > > 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.


    I meant, the interface is written once separately from the class definition,
    sorry!

    > 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.


    Oh definitely, you should! At least give it a test run and see if wants to
    float. The end solution will probably be some sort of conglomeration of
    ideas boiled down into one simple idea.

    Sean O'Dell
     
    Sean O'Dell, Nov 21, 2003
    #12
  13. It occured to me on the bus today...

    Can interfaces be changed at run-time? I think they shouldn't because
    allowing interfaces to be updated any time after they've been created
    would mean that every object implementing the interface would have to be
    re-checked. Maybe one could iterate (or some faster search) through the
    object space (ObjectSpace), but it seems better avoided.

    So this should be an error:

    interface IFoo
    # some stuff
    end

    # ...

    interface IFoo
    # add more stuff to IFoo
    end # => Error, redefinition of interface IFoo

    The reason I say this is because it works differently to the way Ruby
    classes work in a similar situation. It therefore has baring on deriving
    interfaces from classes implicitly (which I'm still thinking about, a
    little bit). However if you do it explicitly and optionally, on a
    particular line of code, I think you're fine because you choose at which
    point to grab the class's interface.

    --
    Greg McIntyre ======[ ]===[ http://puyo.cjb.net ]===
     
    Greg McIntyre, Nov 21, 2003
    #13
  14. Sean O'Dell

    Geoff Youngs Guest

    On Fri, Nov 21, 2003 at 11:17:16AM +0900, Greg McIntyre wrote:
    > Geoff Youngs <> 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.


    It's not perfect, but with a decent interface definition you're less
    likely to be using inheritance that way and you will also have inherited
    the required methods from the parent class anyway, unless you go on to
    re-define them which can't be easily prevented anyway, even in the same
    class.

    > 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...


    That's pretty much what it does. It's possible that something else
    could be acheived with redefinitions of initialize or new or something
    so that a class can't be instantiated until the interface requirements
    are complete, but that might be a bit like overkill...

    It's not perfect, but this approach has met my needs for interfaces so
    far,

    TTFN,


    Geoff.
     
    Geoff Youngs, Nov 21, 2003
    #14
  15. Sean O'Dell

    Geoff Youngs Guest

    On Fri, Nov 21, 2003 at 10:52:19PM +0900, Greg McIntyre wrote:
    > It occured to me on the bus today...


    > Can interfaces be changed at run-time? I think they shouldn't because
    > allowing interfaces to be updated any time after they've been created
    > would mean that every object implementing the interface would have to
    > be re-checked. Maybe one could iterate (or some faster search) through
    > the object space (ObjectSpace), but it seems better avoided.


    > So this should be an error:


    > interface IFoo
    > # some stuff
    > end


    > # ...


    > interface IFoo
    > # add more stuff to IFoo
    > end # => Error, redefinition of interface IFoo


    > The reason I say this is because it works differently to the way Ruby
    > classes work in a similar situation. It therefore has baring on
    > deriving interfaces from classes implicitly (which I'm still thinking
    > about, a little bit). However if you do it explicitly and optionally,
    > on a particular line of code, I think you're fine because you choose
    > at which point to grab the class's interface.


    I see no reason why interfaces shouldn't provide methods themselves. If
    they can provide methods, why shouldn't it be possible to add a utility
    method to an interface (such that it would work with any compliant
    object) to perform a specific job which is not otherwise catered for by
    the interface?

    If you take Enumerable as an example of an existing Ruby interface, you
    know that adding a method to Enumerable affects arrays, hashes, ranges
    and more. This I like. It means that I can add a method to Enumerable
    that logically belongs in Enumerable, rather than having, in effect, a
    method lying around in another class which only operates on Enumerable
    objects, but which claims to be a member of a completely unrelated
    class.

    Changing the required functions for an interface should be a no-no, but
    it would serve little or no point anyway.

    All in all, I would advocate the approach (which seems rubyish to me) of
    assuming that the programmer knows what they're doing and if they wish
    to modify an interface letting them do it.

    TTFN,


    Geoff.
     
    Geoff Youngs, Nov 21, 2003
    #15
  16. Sean O'Dell

    Sean O'Dell Guest

    On Friday 21 November 2003 05:52 am, Greg McIntyre wrote:
    > It occured to me on the bus today...
    >
    > Can interfaces be changed at run-time? I think they shouldn't because
    > allowing interfaces to be updated any time after they've been created
    > would mean that every object implementing the interface would have to be
    > re-checked. Maybe one could iterate (or some faster search) through the
    > object space (ObjectSpace), but it seems better avoided.
    >
    > So this should be an error:
    >
    > interface IFoo
    > # some stuff
    > end
    >
    > # ...
    >
    > interface IFoo
    > # add more stuff to IFoo
    > end # => Error, redefinition of interface IFoo
    >
    > The reason I say this is because it works differently to the way Ruby
    > classes work in a similar situation. It therefore has baring on deriving
    > interfaces from classes implicitly (which I'm still thinking about, a
    > little bit). However if you do it explicitly and optionally, on a
    > particular line of code, I think you're fine because you choose at which
    > point to grab the class's interface.


    Not in my proposal. An interface is completely immutable. For that exact
    reason. =)

    Sean O'Dell
     
    Sean O'Dell, Nov 21, 2003
    #16
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Imran Aziz
    Replies:
    4
    Views:
    8,781
    ljenner01
    Jan 19, 2011
  2. keithb
    Replies:
    3
    Views:
    18,829
    =?ISO-8859-1?Q?G=F6ran_Andersson?=
    May 7, 2006
  3. Replies:
    10
    Views:
    1,258
    Big K
    Feb 2, 2005
  4. Dr Mephesto

    App idea, Any idea on implementation?

    Dr Mephesto, Feb 4, 2008, in forum: Python
    Replies:
    3
    Views:
    733
    Dennis Lee Bieber
    Feb 5, 2008
  5. Replies:
    0
    Views:
    648
Loading...

Share This Page