Interfaces and semantics (or, how to hashpipe a duck)

Semantics, James Thurber notwithstanding, is not a town in Ohio.

I think when Rich says "semantics" he means something that can't
really be checked by a machine -- the "purpose or function," as it
were.

I do sometimes wish there were a way to detect semantics -- but the
best we could do is simply remove the problem a step further.

Warning: I'm tired, so I'm not expressing myself as well as I might
at a different time of day.

For example, imagine that we are concerned with a conceptual "append"
operation. We want to know whether an object is capable of being
appended onto.

Well, a string is "appendable." So is an array. So is a file.

   str << x
   arr << x
   file << x

Aha! Why not just check for << existing?

Oops. There's a Fixnum#<< which does a left shift!

In short, the first three have very similar semantics, but the
last is very different.

I have at times (almost) wished for a thing rather like Java interfaces:

   obj.implements?(Append) # where Append is some sort of interface
                             # whose conceptual semantics are agreed on

Sure, modules in Ruby can serve that purpose. But it's rather
inefficient to have 10-15 modules included in a class (especially when
most methods will be redefined anyway).

But even if we had #implements? -- would it really solve anything? Not
necessarily. We would still have to deal with programmers who were
careless, ignorant, or misinterpreted the docs.

Just the random firings of my neurons. Ignore at your leisure.

Hal Fulton

Hi --

···

On Tue, 8 Jun 2004, Hal Fulton wrote:

Semantics, James Thurber notwithstanding, is not a town in Ohio.

I think when Rich says "semantics" he means something that can't
really be checked by a machine -- the "purpose or function," as it
were.

Yeah, I think you're right. I'd been interpreting the term as a kind
of collective reference to things like signature, return type, etc.
(which is why I'd had trouble finding any of them in Ruby methods :slight_smile:

David

--
David A. Black
dblack@wobblini.net

Here's what I'm working on right now for my own purposes. I've already
applied for a RubyForge project so if others find this useful, they can use
it too. Take a look:

# first class defines the interface
class MyClass
  def method1(a, b, c)
  end

  def method2(a, b, c = nil)
  end

  define_interface(:my_interface, :method1, :method2)
end

# of course it has its own interface
a = MyClass.new
a.has_interface?(:my_interface) => true

# second class simply declares that it implements the interface
class UnrelatedClass
  declare_interface(:my_interface)

  def method1(a, b, c)
  end

  def method2(a, b, c = nil)
  end
end

# it also implements the interface
a = UnrelatedClass.new
a.has_interface?(:my_interface) => true

# the third class declares the interface
# but changes one of the methods' parameters to have no default
class NoncompliantClass
  declare_interface(:my_interface)

  def method1(a, b, c)
  end

  def method2(a, b, c)
  end
end

# because of the method change, it does not implement the interface
a = NoncompliantClass.new
a.has_interface?(:my_interface) => false

I'm writing a little lib in C to do this right now. I'm mostly done. I am
fighting with the Ruby C API's class variable access, otherwise I'd be
finished.

  Sean O'Dell

···

On Monday 07 June 2004 20:13, Hal Fulton wrote:

Semantics, James Thurber notwithstanding, is not a town in Ohio.

I think when Rich says "semantics" he means something that can't
really be checked by a machine -- the "purpose or function," as it
were.

I do sometimes wish there were a way to detect semantics -- but the
best we could do is simply remove the problem a step further.

Hal Fulton wrote:

Semantics, James Thurber notwithstanding, is not a town in Ohio.

I think when Rich says "semantics" he means something that can't
really be checked by a machine -- the "purpose or function," as it
were.

I do sometimes wish there were a way to detect semantics -- but the
best we could do is simply remove the problem a step further.

Warning: I'm tired, so I'm not expressing myself as well as I might
at a different time of day.

For example, imagine that we are concerned with a conceptual "append"
operation. We want to know whether an object is capable of being
appended onto.

Well, a string is "appendable." So is an array. So is a file.

  str << x
  arr << x
  file << x

Aha! Why not just check for << existing?

Oops. There's a Fixnum#<< which does a left shift!

In short, the first three have very similar semantics, but the
last is very different.

I have at times (almost) wished for a thing rather like Java interfaces:

  obj.implements?(Append) # where Append is some sort of interface
                            # whose conceptual semantics are agreed on

Sure, modules in Ruby can serve that purpose. But it's rather
inefficient to have 10-15 modules included in a class (especially when
most methods will be redefined anyway).

But even if we had #implements? -- would it really solve anything? Not
necessarily. We would still have to deal with programmers who were
careless, ignorant, or misinterpreted the docs.

Just the random firings of my neurons. Ignore at your leisure.

Hal Fulton

This is what I was trying to say earlier today. The syntax "<<" in your example is overloaded with regard to semantics (meaning) - it means substantively different things for arrays vs hashes. This is true right out of the box in Ruby for "<<" and "". The only way to avoid the problem, so far as I can see, is to use a syntax which is unique to the semantics you wish to represent - in Ruby that means picking a new method name+#args, because without type information there's nothing else to clue in on.

The solution for Sean is to not use "". Either use an existing method alias which is not semantically overloaded when writing new hash-like classes, or create a new alias (for instance by writing a wrapper method) which is not semantically overloaded for hashes and use that method name for your hash-like classes.

--paul

Let's say I want to implement interfaces using classes (so I can do interface checking with the simple Object#kind_of?). There will be components (which will also be classes). A component can implement one or more interfaces. Method names from different interfaces might clash (e.g. IFoo#quack vs IBar#quack) and we need to be able to choose which interface we want to use from a component.

What's the best way to implement this? My current attempt:

--- BEGIN OF CODE ---
# components will derive from the Component class, to share
# some common code
class Component

   # @implements will contain a list of interfaces that this component
   # implements
   def Component.implements; @implements end
   def implements; self.class.implements end
   def Component.implements?(itf); @implements.include? itf end
   def implements?(itf); self.class.implements? itf end

   # @implementors is a hash, containing the class that implements a
   # certain interface.
   def Component.implementors; @implementors end
   def implementors; self.class.implementors end

   # will return an instance of implementor class
   def use_interface(itf, *args)
     raise ArgumentError unless implements? itf
     raise NotImplementedError unless implementors[itf]
     implementors[itf].new(*args)
   end
end

# IHasFeet is an interface
class IHasFeet
   # s is speed
   def walk(s); raise NotImplementedError end

   # d is the name of a dance
   def entertain(d); raise NotImplementedError end
end

# IHasMouth is an interface
class IHasMouth
   # sp is speed, str is string
   def talk(sp, str); raise NotImplementedError end

   # s is the name of a song
   def entertain(s); raise NotImplementedError end
end

# Human is a component. It implements IHasFeet and IHasMouth.
class Human < Component
   @implements = [IHasFeet, IHasMouth]

   class Human_IHasFeet < IHasFeet
     def walk(s); puts "Walking..." end
     def entertain(d); puts "Can't dance!" end
   end

   class Human_IHasMouth < IHasMouth
     def talk(sp, str); puts str end
     def entertain(s); puts "Singing #{s}..." end
   end

   @implementors = {IHasFeet => Human_IHasFeet,
                    IHasMouth => Human_IHasMouth}
end

# Bear is a component. It implements IHasFeet and IHasMouth.
class Bear < Component
   @implements = [IHasFeet, IHasMouth]

   class Bear_IHasFeet < IHasFeet
     def walk(s); puts "Walking..." end
     def entertain(d); puts "Dancing #{d}..." end
   end

   class Bear_IHasMouth < IHasMouth
     def talk(sp, str); puts "R O A R!" end
     def entertain(s); puts "Can't sing!" end
   end

   @implementors = {IHasFeet => Bear_IHasFeet,
                    IHasMouth => Bear_IHasMouth}
end

# test

p Bear.implements # -> [IHasFeet, IHasMouth]
p Bear.implements? IHasMouth # -> true

bear = Bear.new
p bear.implements # -> [IHasFeet, IHasMouth]
p bear.implements? IHasFeet # -> true

b = bear.use_interface(IHasFeet)
p b.kind_of? IHasFeet # -> true
b.walk(1) # -> Walking...
b.entertain("russian dance") # -> Dancing russian dance...
b = bear.use_interface(IHasMouth)
b.entertain("o canada") # -> Can't dance!
--- END OF CODE ---

The code feels very mechanic and contains a lot of plumbing, but it's pretty much what I wanted (my requirements):

a) a component can implement multiple interfaces;
b) I can pick interfaces from components without fear of conflict;
c) my other code can later check whether something has a feet or a mouth, without explicitly checking its component class (Human or Bear).

Any better suggestion?

···

--
dave

Hal Fulton wrote:

I think when Rich says "semantics" he means something that can't
really be checked by a machine -- the "purpose or function," as it
were.

I do sometimes wish there were a way to detect semantics -- but the
best we could do is simply remove the problem a step further.

For example, imagine that we are concerned with a conceptual "append"
operation. We want to know whether an object is capable of being
appended onto.

Well, a string is "appendable." So is an array. So is a file.

I have at times (almost) wished for a thing rather like Java interfaces:

  obj.implements?(Append) # where Append is some sort of interface
                            # whose conceptual semantics are agreed on

I think I'm going to share my ideas about all this. Oh, and sorry for the heavy quoting, but it's hard to snip well-written text. :slight_smile:

However this also applies to me right now:

Warning: I'm tired, so I'm not expressing myself as well as I might
at a different time of day.

I would really like to do it like this:

EachContract = Contract.new do
   def test(obj)
     assert(obj.respond_to?(:each))
   end
end

AppendContract = Contract.new do
   implicates EachContract

   def test_append(obj)
     assert(obj.respond_to?(:<<))
     initial = ; obj.each { |item| initial << item }
     new_obj = obj.clone; new_obj << "x"
     appended = ; obj.each { |item| appended << item }
     assert(appended.size > initial.size)
     assert(initial.all? { |item| appended.include?(item) })
   end
end

obj =
case obj
   when AppendContract then obj << 5
end

This still needs to be thought to the end, however.

Regards,
Florian Gross

"Hal Fulton" <hal9000@hypermetrics.com> wrote in message

For example, imagine that we are concerned with a conceptual "append"
operation. We want to know whether an object is capable of being
appended onto.

Well, a string is "appendable." So is an array. So is a file.

   str << x
   arr << x
   file << x

Aha! Why not just check for << existing?

Oops. There's a Fixnum#<< which does a left shift!

The harder way is to specify the intended/guaranteed effect of the operation
(without committing to the implementation e.g. post-condition style
contracts).

A much easier improvement is to use meaningful parameter names and treat
them as part of the method selector.

    String#<<:item
    Array#<<:item
    File#<<:item
vs.
    Fixnum#<<:amount

Smalltalk does this. Imho, Ruby should do this when proper keyword arguments
are supported.

Hi,

At Tue, 8 Jun 2004 12:36:28 +0900,
Sean O'Dell wrote in [ruby-talk:102735]:

I'm writing a little lib in C to do this right now. I'm mostly done. I am
fighting with the Ruby C API's class variable access, otherwise I'd be
finished.

See variable.c:

VALUE rb_cvar_defined _((VALUE, ID));
#define RB_CVAR_SET_4ARGS 1
void rb_cvar_set _((VALUE, ID, VALUE, int));
VALUE rb_cvar_get _((VALUE, ID));
void rb_cv_set _((VALUE, const char*, VALUE));
VALUE rb_cv_get _((VALUE, const char*));
void rb_define_class_variable _((VALUE, const char*, VALUE));
VALUE rb_mod_class_variables _((VALUE));
VALUE rb_mod_remove_cvar _((VALUE, VALUE));

···

--
Nobu Nakada

take a look at PyProtocols,
http://peak.telecommunity.com/PyProtocols.html

may be of interest to you. Imo, it's a complex solution to a complex
problem, I'd prefer less general and easyer.

···

il Tue, 8 Jun 2004 17:47:08 +0900, David Garamond <lists@zara.6.isreserved.com> ha scritto::

Let's say I want to implement interfaces using classes (so I can do
interface checking with the simple Object#kind_of?). There will be
components (which will also be classes). A component can implement one
or more interfaces. Method names from different interfaces might clash
(e.g. IFoo#quack vs IBar#quack) and we need to be able to choose which
interface we want to use from a component.

David A. Black wrote:

Hi --

Semantics, James Thurber notwithstanding, is not a town in Ohio.

I think when Rich says "semantics" he means something that can't
really be checked by a machine -- the "purpose or function," as it
were.

Yeah, I think you're right. I'd been interpreting the term as a kind
of collective reference to things like signature, return type, etc.
(which is why I'd had trouble finding any of them in Ruby methods :slight_smile:

Method semantics are about *what* a method does. For a class to be a subtype (i.e. Duck type-able ... is that a word?), it must obey the Liskov Substitution Principle (LSP). In general that means (1) the method names need to be the same, (2) they take the same arguments and (3) they have compatible (but not necessarily identical) semantics. Using respond_to? just checks (1).

I don't have time this morning to say more than this, but I recommend the white papers at objectmentor.com as a starting place for reading about LSP and other design principles. Also Building bug-free O-O software: An introduction to Design by Contract is a good beginner's article on Contracts (which is one way of actually specifying semantics).

···

On Tue, 8 Jun 2004, Hal Fulton wrote:

--
-- Jim Weirich jim@weirichhouse.org http://onestepback.org
-----------------------------------------------------------------
"Beware of bugs in the above code; I have only proved it correct,
not tried it." -- Donald Knuth (in a memo to Peter van Emde Boas)

"Sean O'Dell" <sean@celsoft.com> wrote in message news:<200406072036.21285.sean@celsoft.com>...

···

On Monday 07 June 2004 20:13, Hal Fulton wrote:
> Semantics, James Thurber notwithstanding, is not a town in Ohio.
>
> I think when Rich says "semantics" he means something that can't
> really be checked by a machine -- the "purpose or function," as it
> were.
>
> I do sometimes wish there were a way to detect semantics -- but the
> best we could do is simply remove the problem a step further.

Here's what I'm working on right now for my own purposes. I've already
applied for a RubyForge project so if others find this useful, they can use
it too. Take a look:

# first class defines the interface
class MyClass
  def method1(a, b, c)
  end

  def method2(a, b, c = nil)
  end

  define_interface(:my_interface, :method1, :method2)
end

# of course it has its own interface
a = MyClass.new
a.has_interface?(:my_interface) => true

# second class simply declares that it implements the interface
class UnrelatedClass
  declare_interface(:my_interface)

  def method1(a, b, c)
  end

  def method2(a, b, c = nil)
  end
end

# it also implements the interface
a = UnrelatedClass.new
a.has_interface?(:my_interface) => true

# the third class declares the interface
# but changes one of the methods' parameters to have no default
class NoncompliantClass
  declare_interface(:my_interface)

  def method1(a, b, c)
  end

  def method2(a, b, c)
  end
end

# because of the method change, it does not implement the interface
a = NoncompliantClass.new
a.has_interface?(:my_interface) => false

I'm writing a little lib in C to do this right now. I'm mostly done. I am
fighting with the Ruby C API's class variable access, otherwise I'd be
finished.

  Sean O'Dell

I published an "interface" module a short while back. You can find it
on the RAA or at:

http://ruby-miscutils.sourceforge.net

Regards,

dan

gabriele renzi wrote:

Let's say I want to implement interfaces using classes (so I can do interface checking with the simple Object#kind_of?). There will be components (which will also be classes). A component can implement one or more interfaces. Method names from different interfaces might clash (e.g. IFoo#quack vs IBar#quack) and we need to be able to choose which interface we want to use from a component.

take a look at PyProtocols,
http://peak.telecommunity.com/PyProtocols.html

may be of interest to you. Imo, it's a complex solution to a complex
problem, I'd prefer less general and easyer.

I took a look at PEAK & PyProtocols a few weeks ago. I've also seen Zope3's component architecture some months ago. I heard they will somehow merge their interface/component architecture.

To tell you the truth, I don't like the way they do it. IIRC, Zope3 implements interface as a normal object (instead of a class). Also their notion of a 'component' is not like what I have in mind (which is more like COM's or CORBA's component). Zope's component is more like a 'component instance' instead.

But I agree with you about simpler solution. Interfaces (at least in Java) are basically another hierarchy of class-like/type-like things, separate from the class hierarchy. We just need to define interfaces and tag classes ("components") with them. Classes are the entity closest to interfaces, so I tend to define interface as a Ruby class.

···

--
dave

I have the docs. What's wrong is, in an instance method, I can't seem to
access the class variable from the C API. In Ruby, instance methods can see
the instance variables just fine, so I know that part of my code is working
with them right.

  Sean O'Dell

···

On Monday 07 June 2004 21:07, nobu.nokada@softhome.net wrote:

Hi,

At Tue, 8 Jun 2004 12:36:28 +0900,

Sean O'Dell wrote in [ruby-talk:102735]:
> I'm writing a little lib in C to do this right now. I'm mostly done. I
> am fighting with the Ruby C API's class variable access, otherwise I'd be
> finished.

See variable.c:

VALUE rb_cvar_defined _((VALUE, ID));
#define RB_CVAR_SET_4ARGS 1
void rb_cvar_set _((VALUE, ID, VALUE, int));
VALUE rb_cvar_get _((VALUE, ID));
void rb_cv_set _((VALUE, const char*, VALUE));
VALUE rb_cv_get _((VALUE, const char*));
void rb_define_class_variable _((VALUE, const char*, VALUE));
VALUE rb_mod_class_variables _((VALUE));
VALUE rb_mod_remove_cvar _((VALUE, VALUE));

Mine looks pretty close to how yours works except it verifies the number of
method arguments. Whenever a method is added or removed, the compliance flag
is lowered so the next time has_interface? is called, a complete check is
re-done to be sure the object still complies. Is yours written in C? One
thing I wanted was for this to have as little overhead as possible, so I
didn't feel like I was slowing down my project too much by calling it
everywhere.

  Sean O'Dell

···

On Tuesday 08 June 2004 06:04, Daniel Berger wrote:

"Sean O'Dell" <sean@celsoft.com> wrote in message

I published an "interface" module a short while back. You can find it
on the RAA or at:

Hi,

At Tue, 8 Jun 2004 23:32:28 +0900,
Sean O'Dell wrote in [ruby-talk:102779]:

I have the docs. What's wrong is, in an instance method, I can't seem to
access the class variable from the C API. In Ruby, instance methods can see
the instance variables just fine, so I know that part of my code is working
with them right.

  VALUE cvar = rb_cvar_get(CLASS_OF(obj), rb_intern("@@cvar"));

and so on.

···

--
Nobu Nakada

"Sean O'Dell" <sean@celsoft.com> wrote in message news:<200406080736.32485.sean@celsoft.com>...

···

On Tuesday 08 June 2004 06:04, Daniel Berger wrote:
> "Sean O'Dell" <sean@celsoft.com> wrote in message
>
> I published an "interface" module a short while back. You can find it
> on the RAA or at:

Mine looks pretty close to how yours works except it verifies the number of
method arguments. Whenever a method is added or removed, the compliance flag
is lowered so the next time has_interface? is called, a complete check is
re-done to be sure the object still complies. Is yours written in C? One
thing I wanted was for this to have as little overhead as possible, so I
didn't feel like I was slowing down my project too much by calling it
everywhere.

  Sean O'Dell

It's pure Ruby. I don't think adding arity checks and hooks for
method_added/method_removed would be difficult.

Regards,

Dan

What I'm doing is setting the class variables in the class definition, then
trying to use them in an instance method. In Ruby, the instance methods can
see the class variables just fine. In C, the API says they don't exist.

  Sean O'Dell

···

On Tuesday 08 June 2004 07:37, nobu.nokada@softhome.net wrote:

Hi,

At Tue, 8 Jun 2004 23:32:28 +0900,

Sean O'Dell wrote in [ruby-talk:102779]:
> I have the docs. What's wrong is, in an instance method, I can't seem to
> access the class variable from the C API. In Ruby, instance methods can
> see the instance variables just fine, so I know that part of my code is
> working with them right.

  VALUE cvar = rb_cvar_get(CLASS_OF(obj), rb_intern("@@cvar"));

Oh! I see what you mean now; I overlooked the CLASS_OF part. Thanks, I'll
try that.

  Sean O'Dell

···

On Tuesday 08 June 2004 07:37, nobu.nokada@softhome.net wrote:

Hi,

At Tue, 8 Jun 2004 23:32:28 +0900,

Sean O'Dell wrote in [ruby-talk:102779]:
> I have the docs. What's wrong is, in an instance method, I can't seem to
> access the class variable from the C API. In Ruby, instance methods can
> see the instance variables just fine, so I know that part of my code is
> working with them right.

  VALUE cvar = rb_cvar_get(CLASS_OF(obj), rb_intern("@@cvar"));

Probably wouldn't, but I just finished mine and it's released, and it's in C.
I don't know what to do about the name clash. I can't think of another name
that works as well, and I have to move on to some actual work here.

  Sean O'Dell

···

On Tuesday 08 June 2004 11:23, Daniel Berger wrote:

"Sean O'Dell" <sean@celsoft.com> wrote in message
news:<200406080736.32485.sean@celsoft.com>...

> On Tuesday 08 June 2004 06:04, Daniel Berger wrote:
> > "Sean O'Dell" <sean@celsoft.com> wrote in message
> >
> > I published an "interface" module a short while back. You can find it
> > on the RAA or at:
>
> Mine looks pretty close to how yours works except it verifies the number
> of method arguments. Whenever a method is added or removed, the
> compliance flag is lowered so the next time has_interface? is called, a
> complete check is re-done to be sure the object still complies. Is yours
> written in C? One thing I wanted was for this to have as little overhead
> as possible, so I didn't feel like I was slowing down my project too much
> by calling it everywhere.
>
> Sean O'Dell

It's pure Ruby. I don't think adding arity checks and hooks for
method_added/method_removed would be difficult.

If you are in an instance method in C you get the obj as the first param.
The code above references the CLASS_OF your obj and gets its class variable
@@whatever. Isn't that what you want?

···

On 6/8/04 10:42 AM, "Sean O'Dell" <sean@celsoft.com> wrote:

On Tuesday 08 June 2004 07:37, nobu.nokada@softhome.net wrote:

Hi,

At Tue, 8 Jun 2004 23:32:28 +0900,

Sean O'Dell wrote in [ruby-talk:102779]:

I have the docs. What's wrong is, in an instance method, I can't seem to
access the class variable from the C API. In Ruby, instance methods can
see the instance variables just fine, so I know that part of my code is
working with them right.

  VALUE cvar = rb_cvar_get(CLASS_OF(obj), rb_intern("@@cvar"));

What I'm doing is setting the class variables in the class definition, then
trying to use them in an instance method. In Ruby, the instance methods can
see the class variables just fine. In C, the API says they don't exist.

Sean O'Dell