S
Sean O'Dell
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
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