[Prev][Next][Index][Thread]

Re: Need help with Class-Allocated Slots



rwk@americom.com <rwk@americom.com> wrote:
> Neel Krishnaswami <neelk@alum.mit.edu> wrote:
> > 
> > The big problems with this that is it's hard to know what to do if
> > there is a specialized method shadowing the basic getter. [...]
> 
> There could (ought to) be a way to qualify the ambiguous reference
> to make it clear which reference is being requested, "method foo" of
> "slot foo". In the absence of an unambiguous reference the system
> could simply flag it as an error.

I'm not so sure of this, actually. The unification of slot access and
method dispatch is one of the most elegant features of Dylan, and I'd
hate to see it break without a really good rationale. IMO, this is the
sort of thing that should either be part of a full-fledged MOP or not
present at all.

> In practice, conflicts like this are less of a problem than the lack of
> having the feature in the first place.  Multiple Inheritance can cause
> conflicts as well, but that doesn't mean it should not be implemented
> (which is the approach Java took with MI).

In this case, I think that if you need to access class slots before
there are instances, you should use a module variable, like:

  define variable *bar* = 9;

  define method bar(obj :: <foo>) => (value)
    *bar*
  end method;

  define method bar-setter(value, obj :: <foo>) => (value)
    *bar* := value
  end method;

Then if you need the bare "class slot", you can access the variable
directly. If all this seems kind of grotty to you, then a little
macrology can make all the dirt go away:

  define macro class-slot-definer
    {define class-slot (?class:name, ?:name) as ?:expression}
      => {define variable "*!*" ## ?name ## "*!*" = ?expression;
          define method ?name (obj :: ?class) => (value)
            "*!*" ## ?name ## "*!*"
          end method;
          define method ?name ## "-setter" (value, obj :: ?class) => (value)
            "*!*" ## ?name ## "*!*" := value;
          end method;
          define method class-slot(class :: subclass(?class), gf == ?name)
            "*!*" ## ?name ## "*!*"
          end method;
          define method class-slot-setter(value,
                                          class :: subclass(?class),
                                          gf == ?name) => (value)
            "*!*" ## ?name ## "*!*" := value;
          end method class-slot-setter;}
  end macro;

Use it like this:

  define class <foo> (<object>)
  end class <foo>;
  
  define class-slot(<foo>, bar) as 10;
  
  define method main(appname, #rest arguments)
    local method test(heading, val-1, val-2)
  	    format-out(heading);
  	    format-out("\n");
  	    format-out("    x.bar is %=\n", val-1);
  	    format-out("    class-slot(<foo>, bar) is %=\n", val-2);
  	  end method test;
  
    let x = make(<foo>);
    test("define class-slot(<foo>, bar) as 10;",
         x.bar, class-slot(<foo>, bar));
  
    x.bar := 15;
    test("x.bar := 15;", 
         x.bar, class-slot(<foo>, bar));
  
    class-slot(<foo>, bar) := 21;
    test("class-slot(<foo>, bar) := 21;", 
         x.bar, class-slot(<foo>, bar));
  end method main;

Which should output something like:

  define class-slot(<foo>, bar) as 10;
      x.bar is 10
      class-slot(<foo>, bar) is 10
  x.bar := 15;
      x.bar is 15
      class-slot(<foo>, bar) is 15
  class-slot(<foo>, bar) := 21;
      x.bar is 21
      class-slot(<foo>, bar) is 21

This should pretty much serve your needs, without getting into the
strange territory. (Addition of stuff to deal with type declarations,
each-subclass slots, and so on are left as an exercise for the
reader. :)


Neel



Follow-Ups: References: