[Posted and mailed]

[Tobias replied to me privately, then asked me to forward his reply 
here.  Instead I will just keep it all quoted :-]

 > -----Original Message-----
 > From: Tobias Oberstein [mailto:[EMAIL PROTECTED]]
 > Sent: Saturday, 2 February 2002 4:15 AM
 > To: [EMAIL PROTECTED]
 > Subject: Re: design patterns for "parameters" in ContractIDs
 >
 >
 > > It is not clear what you are asking.  contract IDs are unique(ish)
 > > strings.  For every known contract ID, there is a class ID, which
 > > uniquely identifies a component, as implemented in some source file
 > > (generally .c/cpp or .js)
 >
 > That has been clear to me - what wasn't clear to me from the beginning
 > is that different ContractIDs can be mapped to one CLSID, as
 > with
 >
 > @mozilla.org/uriloader/content-handler;1?type=text/plain
 > @mozilla.org/uriloader/content-handler;1?type=text/xml
 > @mozilla.org/uriloader/content-handler;1?type=text/jpeg
 > ..
 >
 > and still it's a mystery to me (even after reading the sources) how
 > in this particular case the single implementation (XPCOM class) behind
 > this CLSID gets information about the ?type=XXX it was
 > instantiated for.
 >
 >
 > > So all you need to do is register an xpcom component with
 > > the contract
 > > ID "@xyz.com/some-module/foobar;1?param1=small;param2=blue"
 >
 > and one for param1=big;param2=red and one for param1=big;param2=green
 > and so on .. what if param1 can take values from {0,1,2,3,... 2^32-1}

It seemed to me from your original question that your data sets were 
fairly small.  Thus, you may end up with 15-20 different components, but 
that may be fine.

As you suggested, C++ templates could probably be used to do alot of 
that.  You create a base class, and have a template define a sub-class, 
that both create a contract ID, and override an Init() virtual with the 
necessary "params".

 >
 > this is case 1.b.i in my statement, which is indeed sloppy and not
 > very precise by the way ;)
 >
 > > > Further, it should be acceptable that a client may _not_ resort
 > > > parameters like this:
 > > >
 > > > "@xyz.com/some-module/foobar;1?param2=blue;param1=small"
 > >
 > > No problem - that is a different, unknown string.
 >
 > well, no practical problem - though quite non-intuitive not to
 > be allowed to reorder _named_ parameters - but agreed.. its
 > practically irrelevant.
 >
 > >
 > > > 1. Are there established patterns of design to realize such stuff?
 > > > a) .. where there is one implementing class and the ContractID
 > > > parameters are used to initialize some member vars of the
 > > > implementing class
 > >
 > > The contract ID generally exists in a source file.  One source file
 > > could implement many components.
 >
 > seems we're talking about different things. I tried to make the following
 > point: I don't want to write one implementation per parameter 
combination.
 >
 > I want to have one implementing class, taking the parameters either in
 > a constructor
 >
 > class MyClass : public ISomeIfc
 > {
 > MyClass(int param1, int param2);
 > }
 >
 > or have a Init(int param1, int param2) method _automatically_ called
 > with the values the client provided implicitely in the ContractID.
 >
 > I don't want to write code for:
 >
 > class MyClass_BlueBig;
 > class MyClass_BlueSmall;
 > class MyClass_RedBig;
 > ...
 >
 >
 > >
 > > > b) .. where there are multiple implementing classes and the
 > > > parameters are used to choose the appropriate implementation
 > >
 > > It is only ever done (as far as I know) using different contract IDs.
 > > Not params as such, but call it that if you like :)
 >
 > Well, they _look_ like parameters .. even if there are just opaque
 > ContractIDs. Agreed.
 >
 > >
 > >
 > > > i) .. and the different implementations are manually programmed
 > > > implementation classes
 > >
 > > Not sure what you are asking.
 >
 > This was ment versus C++ templates, which I look at as some kind
 > of "compiler written".
 > But this case is and was clear to me .. I just provided it in the list
 > to make this list kind of "exhaustive" from my point of view.
 >
 > >
 > > >
 > > > ii) .. and the different implementations are compile time
 > > > generated via C++ template classes
 > >
 > > I can't recall seeing any such samples, and according to the C++ style
 > > guide (see mozilla.org) that would not be portable.  Could be done
 > > pretty simply though.
 >
 > I'm aware of the doc you mention. I completely agree with it when looking
 > from the full-blown Mozilla project view, even today - as opposed to some
 > discussion which took place on /. For my personal aims/project I probably
 > will relax this a little bit:
 >
 > allow "simple" C++ templates:
 > * no template template parameters
 > * no member templates
 > * possibly partial specialization
 >
 > But this whole point is really secondary.
 >
 > >
 > > > 2. If there are different ways of doing it, what questions should
 > > > I ask myself in choosing my way?
 > >
 > > Should you be using javascript or Python?  Or using simple C++
 > inheritance?
 >
 > I'm implementing components in C++ and using Python as a scripting
 > frontend.

Consider using PyXPCOM :-)  It works well.  See below for an example :)

 >
 > >
 > > [snipped way more code than I have time to play with]
 >
 > You're right. I should have taken more time in stating my questions more
 > precise.
 >
 > >
 > > Mark.
 > >
 >
 > Thanks Mark,
 >
 > Toby.
 >

Below is some gratuitous PyXPCOM hacking.  It pulls a number of tricks - 
feel free to ask if you care about any of it :)  It allows you to define 
all your functionality in a base class.  This base class has access to 
your arbitary parameters.

It creates 2 such objects, with contract IDs 
"@test.com/WorkHorse?foo=bar;spam=eggs" and 
"@test.com/WorkHorse?foo=green;spam=vikings"

When you run regxpcom over this, it reports:
-
Registering: ParamClass: foo=bar;spam=eggs
Registering: ParamClass: foo=green;spam=vikings
-
When you execute the test code (included in the same source), it reports:
-
Workhorse object created.  My params are {'foo': 'bar', 'spam': 'eggs'}
Workhorse object created.  My params are {'foo': 'green', 'spam': 'vikings'}
Created the objects OK!
-

The source code is below.

Mark.

# Parameterised contract IDs.
import new

# Our class with all the functionality.
# self._params_ will hold our contract ID's params.
class _Workhorse:
     _com_interfaces_ = "nsISupports"
     def __init__(self):
         print "Workhorse object created.  My params are", self._params_

# Helper function that creates new class objects
def MakeParameterisedClass( params, classid):
     dict = {}
     param_string = ";".join(["%s=%s" % i for i in params.items()])
     dict['_reg_contractid_'] = "@test.com/WorkHorse?" + param_string
     dict['_reg_clsid_'] = classid
     dict['_params_'] = params
     name = "ParamClass: " + param_string
     klass = new.classobj(name, (_Workhorse,), dict)
     return klass

# Create all the classes - specify the params, and a CLSID.
class1 = MakeParameterisedClass( {"foo" : "bar", "spam" : "eggs"}, 
"{999a4477-e478-45ea-a789-35268625510a}")
class2 = MakeParameterisedClass( {"foo" : "green", "spam" : "vikings"}, 
"{7a5921f3-a056-4092-b238-cb7fa50e324e}")

# self-test code.
if __name__=='__main__':
     from xpcom import components
     ob = 
components.classes["@test.com/WorkHorse?foo=bar;spam=eggs"].createInstance()
     ob = 
components.classes["@test.com/WorkHorse?foo=green;spam=vikings"].createInstance()
     print "Created the objects OK!"


Reply via email to