Object method ensemble

I'd like to be able to define a method that was an ensemble. I can hack it by using the namespace ensemble command in the objects namespace and defining procs, but doing so bypasses the normal object mechanism. The syntax I'd like to use is something like:

oo::class create C {
  method {foo boo} { args } { puts "boo called with $args" }
  method {foo goo} { args } { puts "goo called with $args" }
  method {foo doo} { args } { puts "goo called with $args" }
}

which could be invoked as:

(test) 1 % set o [C new]
::oo::Obj12
(test) 2 % $o foo boo 1
boo called with 1
(test) 3 % $o foo goo 2
goo called with 2
(test) 4 % $o foo doo 3
doo called with 3
(test) 5 % $o foo bar 4
unknown or ambiguous subcommand "bar": must be boo, doo, or goo
(test) 6 %

What I can do now to get the effect is this:

oo::class create C {
  constructor { args } {
    proc boo { args } { puts "boo called with $args" }
    proc goo { args } { puts "goo called with $args" }
    proc doo { args } { puts "doo called with $args" }
    namespace ensemble create -command foo -subcommands [list boo goo doo]
    ::oo::objdefine [self] forward foo [namespace current]::foo
  }
}

Which results in an very un-object-like object. Am I missing the "right" way to do this?

Thanks, Paul


if 0 {

FM Well, as I see it, you simply create a class which build an ensemble inside and forwards commands to it. This is quite the same as the folowing code :

}

oo::class create EnsembleObject {
    constructor { args } {
        namespace eval say {
            namespace eval hello {
                proc to {args} {
                    puts hello\ $args
                    [namespace parent [namespace parent [namespace current]]]::my hello $args
                }
                namespace export *
                namespace ensemble create
            }
            namespace export *
            namespace ensemble create
        }
        ::oo::objdefine [self] forward say [namespace current]::say
    }
    method hello args  {
        set args [linsert [linsert {*}$args 1 method] 2 call]
    }
}

set e [EnsembleObject new]

$e say hello to you from ensemble object
if 0 {

FM Maybe, there is some things I don't understand too, and I'd like an answer to your question too. The only way to do chain command whith object I found is this code :

}
oo::class create NestObject {
    constructor {args} {
        oo::class create Neste1 {
            constructor {args} {
                oo::class create Neste2 {
                    method to {args} {
                        puts hello\ $args
                    }
                }
                Neste2 create hello
                ::oo::objdefine [self] forward hello [namespace current]::hello
            }
        }
        Neste1 create say
        ::oo::objdefine [self] forward say [namespace current]::say
    }
}

set n [NestObject new]
$n say hello to you from nested objet

if 0 {

FM It's not as clear as namespace ensemble I find. It's not easy to call a method from an upper object.

}

dkf - 2009-07-10 07:02:00

This is SNIT-like methods, and I've not had a chance to make them work. (I've got them in one of my sandboxes, but haven't managed to make the introspection nice; they've been put on one side though for the past few months...)


mpdanielson Thanks for the update, Donal. I'll just keep doing it the ugly way then, until something better comes along.


2016-06-27:

oo::class create C {
    constructor args {
        oo::object create foo
        oo::objdefine foo {
            method boo args {puts "boo called with $args"}
            method goo args {puts "goo called with $args"}
            method doo args {puts "doo called with $args"}
        }
    }
    forward foo foo
}

% set c [C new]
% $c foo boo a b c
boo called with a b c

MSA:

oo::class create C1 {
   constructor {args} {
      ::oo::objdefine [self] { 
         method unknown  {args} {
            set cmd _[lindex $args 0]_[lindex $args 1]
            if {!($cmd in [info object methods [self] -private -all])} {
               return -code error -errorinfo "unknown method [self] [lindex $args 0] [lindex $args 1]"
            }
            my $cmd {*}[lrange $args  2 end]
         }
      }
   }
   method _cmd1_subCmd1 {a1} {
      puts _cmd1_subCmd1:a1=$a1
   }
}
% set o [C1 new 1]
% $o cmd1 subCmd1 1

See Also

ycl shelf
Uses the -parameters option to namespace ensemble to accomplish this task (ycl shelf is not implemented via TclOO).