How to make an parametrized enum build macro? - macros

Now Solved
I want to build an enum with a macro, including defining its type parameters.
There are a couple of sources describing adding enum fields with macros , but I havent found any which describe how to build an enum with specified parameter types using macros. There is a documentation entry made for limitations of macros here regarding parameter types, but that is still left empty.
The idea is to use a macro to generate a specified number of Either enums with increasing amount of parameter types.
//Either.hx
#:build(macros.build.EitherBuildMacro.build(10))
// enum Either {} <- this isnt sufficient as we need to generated several
// enums (in this example 10 of them) with parameter types...
//And it should generate
enum Either2<A,B>{
_1(value:A);
_2(value:B);
}
enum Either3<A,B,C>{
_1(value:A);
_2(value:B);
_3(value:C);
}
enum Either4<A,B,C,D>{
_1(value:A);
_2(value:B);
_3(value:C);
_4(value:D);
}
//etc until enum Either10<A,B,C,D,E,F,G,H,I,J>
As I showed earlier in this post there is an article describing how to add fields, but not types. I am clueless how to set these parameter types by a macro and it seems like there are some limitations, yet undocumented. Any pointers which command to use for that are highly appreciated. Defining series of Enums with increasing parameterization is typically something you rather want to do with build macros, than to do by hand. Especially since you could pare each macro generated EitherN with a macro generated OneOfN abstract
abstract OneOf2<A, B>(Either<A, B>) from Either<A, B> to Either<A, B> {
#:from inline static function fromA<A, B>(value:A):OneOf<A, B> {
return _1(a);
}
#:from inline static function fromB<A, B>(value:B):OneOf<A, B> {
return _2(b);
}
#:to inline function toA():Null<A> return switch(this) {
case _1(value): value;
default: null;
}
#:to inline function toB():Null<B> return switch(this) {
case _2(value): value;
default: null;
}
}
abstract OneOf3<A, B, C>(Either<A, B, C>) from Either<A, B, C> to Either<A, B, C> {
#:from inline static function fromA<A, B, C>(value:A):OneOf<A, B, C> {
return _1(value);
}
#:from inline static function fromB<A, B, C>(value:B):OneOf<A, B, C> {
return _2(value);
}
#:from inline static function fromC<A, B, C>(value:C):OneOf<A, B, C> {
return _3(value);
}
#:to inline function toA():Null<A> return switch(this) {
case _1(value): value;
default: null;
}
#:to inline function toB():Null<B> return switch(this) {
case _2(value): value;
default: null;
}
#:to inline function toC():Null<C> return switch(this) {
case _3(value): value;
default: null;
}
}
//etc
The same idea would be handy to generate series of Tuples and Functions with increasing amount of parameter types. Would be a efficient and flexible way to generate the right amount of enums, abstracts and typedefs

#:build() indeed isn't the right approach here, since that just builds one particular type. Instead, you could use an initialization macro in combination with Context.defineType():
--macro Macro.init()
import haxe.macro.Context;
class Macro {
public static function init() {
for (i in 2...11) {
Context.defineType({
pack: [],
name: "Either" + i,
pos: Context.currentPos(),
kind: TDEnum,
fields: [
for (j in 0...i) {
name: "_" + (j + 1),
kind: FFun({
args: [
{
name: "value",
type: TPath({
name: String.fromCharCode(65 + j),
pack: []
})
}
],
ret: null,
expr: null
}),
pos: Context.currentPos()
}
],
params: [
for (j in 0...i) {
name: String.fromCharCode(65 + j)
}
]
});
}
}
}
With -D dump=pretty you can see that this generates Either2-10:
With for instance Either2.dump looking like this:
#:used
enum Either2<A : Either2.A,B : Either2.B> {
_1(value:Either2.A);
_2(value:Either2.B);
}
Alternatively, you could consider using #:genericBuild() in combination with a Rest type parameter. That would essentially do the same and still use Context.defineType(), with a few advantges:
it would allow you to avoid encoding the number of type parameters into the type name (so it would just be Either instead of Either2 / 3 / etc)
the amount of type parameters would not be limited to an arbitrary amount such as 10
types would only be generated "on demand"
You can find an example here.

Related

Using local variables in function built with haxe macro

I have a LangBuilder macro class; it's used to build a langObjects:Map<String, Dynamic> of texts in various languages at compile time, and inject this structure in classes via #:build macro. Every item of the Map has a field for every language supported. So the result is:
#:build(LangBuilder.build())
class Lang{}
trace(Lang.langObjects["hello-world"].en); //outputs "Hello World!"
trace(Lang.langObjects["hello-world"].it); //outputs "Ciao Mondo!"
This works perfectly, but I thought I could make a cleaner job hiding the langObjects structure using a function getLangText with arguments the id of the text (e.g. "hello-world") and the language code (e.g. "it").
So I'm trying to add this function to classes:
public static function getLangText(id:String, lang:String)
Its non-macro version could be expressed as:
public static function getLangText(id:String, lang:String){
var _langObj_id = langObjects[id];
switch(lang){
case "it":
return _langObj_id.it;
case "en":
return _langObj_id.en;
}
return "Missing Translation";
If i translate this function as a macro with this code:
var code = macro {
var _langObj_id = langObjects[$i{"id"}];
switch($i{"lang"}){
case "it":
return _langObj_id.it;
case "en":
return _langObj_id.en;
}
return "Missing translation";
};
var myFunc:Function = {
args: [{
name: "id",
type: TPath({name: "String", pack: []}),
meta: null
},
{
name: "lang",
type: TPath({name: "String", pack: []}),
meta: null
}],
ret: (macro:String),
expr: macro $code
};
fields.push({
pos: Context.currentPos(),
name: "getLangText",
meta: null,
kind: FieldType.FFun(myFunc),
doc: null,
access: [Access.APublic, Access.AStatic]
});
... it works without problems. However I would like to know how it could be written without the switch, to make it more flexible and to learn something about haxe macros. I have seen some examples where fields could be accessed in macros with $p{} or with object.$fieldName. However the haxe manual warns that the second form could be used only for simple identifiers; for example object.${fieldName} would not work.
So I try this code:
var code = macro {
var l:String = $i{"lang"};
var _langObj_id = langObjects[$i{"id"}];
return _langObj_id.$l;
};
The compiler gives an error
Unknown identifier : l
on the line containing return _langObj_id.$l;.
Then i tried to use the $p{} reification:
var code = macro {
var _langObj_id = langObjects[$i{"id"}];
return macro $p{["_langObj_id", $i{"lang"}]};
};
But the error is similar:
Unknown identifier : lang
I can surely change the langObjects structure to Map<String, Map<String, String>> and then change the code to:
var code = macro {
return macro langObjects[$i{"id"}][$i{"lang"}];
};
I think this would work, but now i'm trying to understand why both _langObj_id.$lang and $p{["_langObj_id", $i{"lang"}]} wouldn't work, and what would be the correct way to access a field in a situation like that.
The value of the lang parameter is not known at compile- / macro-time, so I don't see how you could generate a field access expression like langObjects["mytext"].en. At runtime when getLangText() is actually called, lang could be "en", or anything else. So that would still require a switch-case, if-else-chain or reflection to handle all the possible values.
If instead of using being created by a build macro, getLangText() was an expression macro / a macro function, the function call would be evaluated at compile-time, and be replaced with the expression it returns. That would allow you to generate the appropriate field access expression based on the parameters. It could look something like this:
class Macro {
public static var langObjects = ["mytext" => {en: "hello", de: "hallo"}];
public static macro function getLangText(id:String, lang:String) {
return macro {
var langObject = Macro.langObjects[$v{id}];
langObject.$lang;
}
}
}
class Main {
static function main() {
trace(Macro.getLangText("mytext", "en"));
trace(Macro.getLangText("mytext", "de"));
}
}
Compiles to the following on the JS target:
Main.main = function() {
var langObject = Macro.langObjects.get("mytext");
console.log("source/Main.hx:3:",langObject.en);
var langObject1 = Macro.langObjects.get("mytext");
console.log("source/Main.hx:4:",langObject1.de);
};
Perhaps that's what you're looking for? Hard to say without knowing what problem you're trying to solve.

Is it possible to use template arguments in virtual function in modern C++?

I used to do C++ development several years ago and back then I found it difficult to combine template programming with OOP. Currently I program in Swift and I tried doing some of the things I struggled with then.
This Swift code will illustrate the problem:
// protocol is like Java interface or C++ pure virtual base class
protocol Log {
// want to able to add elements from a collection of Ints, but
// it should be any sort of collection that
// can be treated as a sequence
func add<T: SequenceType where T.Generator.Element == Int>(values: T)
}
class DiscreteLog: Log {
var vals: [Int] = []
func add<T: SequenceType where T.Generator.Element == Int>(values: T) {
for v in values {
vals.append(v)
}
}
}
class ContinousLog: Log {
var vals: [Double] = []
func add<T: SequenceType where T.Generator.Element == Int>(values: T) {
for v in values {
vals.append(Double(v))
}
}
}
// I don't have to know whether the log is Continuous or Discrete
// I can still add elements to it
var log: Log = ContinousLog()
log.add([1, 2, 3])
// and elements can come from any kind of sequence, it does not need
// to be an array
log.add(["four": 4, "five: 5].values)
So the problem is that if the C++ code defined as as:
virtual void add(vector<Int> elements>)
Then sure I could have multiple subclasses implement this method, but I could never provide anything but vectors as arguments.
I could try changing it to something more generic using iterator:
virtual void add(vector<Int>::iterator elements>)
But I am still limited to using vector iterators. So I guess I would have to write something like:
template<typename Iterator>
virtual void add(Iterator elements>)
But that will give compile errors as template based arguments are not allowed for virtual methods.
Anyway I wondered if this sort of thing is possible in modern C++.
C++ templates and C#/Swift/Java generics are different things.
They are both "pattern code" in a sense (they are patterns that generate code), but C#/Swift/Java generics use type erasure and "forget" almost everything about the types they work with, while C++ templates are elephants. And elephants never forget.
It turns out that can make an elephant forget, but you have to tell it to. The technique of "forgetting" about details of a type is known as "type erasure" or "run time concepts".
So you want to type erase down to the concept of "a sequence of integers". You want to take any type, so long as it is a sequence of integers, and be able to iterate over it. Seems fair.
boost has such type erasures. But who wants to always rely on boost?
First, type erase an input iterator:
template<class T>
struct input_iterator:
std::iterator<
std::input_iterator_tag, // category
T, // value
std::ptrdiff_t, // distance
T*, // pointer
T // reference
>
{
struct erase {
virtual void advance() = 0;
virtual erase* clone() const = 0;
virtual T get() const = 0;
virtual bool equal(erase const& o) = 0;
virtual ~erase() {}
};
std::unique_ptr<erase> pimpl;
input_iterator(input_iterator&&)=default;
input_iterator& operator=(input_iterator&&)=default;
input_iterator()=default;
input_iterator& operator++() {
pimpl->advance();
return *this;
}
input_iterator operator++(int) {
auto copy = *this;
++*this;
return copy;
}
input_iterator(input_iterator const& o):
pimpl(o.pimpl?o.pimpl->clone():nullptr)
{}
input_iterator& operator=(input_iterator const&o) {
if (!o.pimpl) {
if (pimpl) pimpl->reset();
return *this;
}
pimpl = std::unique_ptr<erase>(o.pimpl->clone());
return *this;
}
T operator*() const {
return pimpl->get();
}
friend bool operator==( input_iterator const& lhs, input_iterator const& rhs ) {
return lhs.pimpl->equal(*rhs.pimpl);
}
friend bool operator!=( input_iterator const& lhs, input_iterator const& rhs ) {
return !(lhs==rhs);
}
template<class It>
struct impl:erase{
It it;
impl(impl const&)=default;
impl(It in):it(std::move(in)){}
virtual void advance() override { ++it; }
virtual erase* clone() const override { return new impl(*this); }
virtual T get() const override { return *it; }
virtual bool equal(erase const& o) override {
return static_cast<impl const&>(o).it == it;
}
};
template<
class It,
class=std::enable_if<
std::is_convertible<
typename std::iterator_traits<It>::reference,
T
>{}
>
>
input_iterator(It it):pimpl( new impl<It>{it} ) {}
}; // input_iterator
Next, have a range template. This is a container that stores non-type erased iterators, and exposes enough to iterate over those iterators.
template<class It>
struct range {
It b; It e;
It begin() const { return b; }
It end() const { return e; }
range() = default;
range(It start, It finish):b(std::move(start)),e(std::move(finish)) {};
range(range&&)=default;
range(range const&)=default;
range& operator=(range&&)=default;
range& operator=(range const&)=default;
template<class R,
class R_It=std::decay_t<decltype(std::begin(std::declval<R>()))>,
class=std::enable_if< std::is_convertible<R_It, It>{} >
>
range( R&& r ):
range(std::begin(r), std::end(r))
{} // TODO: enable ADL begin lookup
};
The above type is really basic: C++1z has better ones, as does boost, as do I have in my own code base. But it is enough to handle for(:) loops, and implicit conversion from containers with compatible iterators.
Finally our sequence type:
template<class T>
using sequence_of = range<input_iterator<T>>;
Wait, that's it? Nice, those types compose well!
And barring errors, we are done.
Your code now would take a sequence_of<int>, and they could pass a std::vector<int> or std::list<int> or whatever.
The input_iterator type-erasure type-erases any iterator down to getting a T via *, ==, copy, and ++ advance, which is enough for a for(:) loop.
The range<input_iterator<int>> will accept any iterable range (including containers) whose iterators can be converted to an input_iterator<int>.
The downside? We just introduced a bunch of overhead. Each method goes through virtual dispatch, from ++ to * to ==.
This is (roughly) what generics do -- they type-erase down to the requirements you give it in the generic clause. This means they are working with abstract objects, not concrete objects, so they unavoidably suffer performance penalties of this indirection.
C++ templates can be used to generate type erasure, and there are even tools (boost has some) to make it easier. What I did above is a half-assed manual one. Similar techniques are used in std::function<R(Args...)>, which type-erases down to (conceptually) {copy, call with (Args...) returning R, destroy} (plus some incidentals).
live example.
(The code above freely uses C++14.)
So the C++ equivalent Log is:
struct Log {
virtual void add(sequence_of<int>) = 0;
virtual ~Log() {}
};
Now, the type erasure code above is a bit ugly. To be fair, I just implemented a language feature in C++ without direct language support for it.
I've seen some proposals to make type erasure easier in C++. I do not know the status of those proposals.
If you want to do your own, here is an "easy" way to do type erasure in 3 steps:
First, determine what operations you want to erase. Write the equivalent of input_iterator<T> -- give it a bunch of methods and operators that do what you want. Be sparse. Call this the "external type". Ideally nothing in this type is virtual, and it should be a Regular or Semi-regular type (ie, it should behave value-like, or move-only-value-like). Don't implement anything but the interface yet.
Second, write an inner class erase. It provides a pure-virtual interface to a set of functions that could provide what you need in your external type.
Store a unique_ptr<erase> pimpl; within the external type. Forward the methods you expose in the external type to the pimpl;.
Third, write an inner template<class X> class impl<X>:erase. It stores a variable X x;, and it implements everything in erase by interacting with X. It should be constructable from an X (with optional perfect forwarding).
You then create a perfect forwarding constructor for the external type that creates its pimpl via a new impl<X>(whatever). Ideally it should check that its argument is a valid one via SFINAE techniques, but that is just a qualify of implementation issue.
Now the external type "erases" the type of any object it is constructed from "down to" the operations you exposed.
Now, for your actual problem, I'd write array_view or steal std::experimental::array_view, and restrict my input to be any kind of contiguous buffer of data of that type. This is more performant, and accepting any sequence is over engineering unless you really need it.

Get Class from string -- Call function by string name

OK, what I'm trying to do is fairy complicated, but I'll try to explain.
Let's say we want (at compile-time) all derivedMembers of class someClass. Then we'd simply do :
const string[] methods = [__traits(derivedMembers,someClass)];
Now, how could we get someClass from "someClass"? (yep, its string representation).
Let me explain a bit more what I'm trying to do :
I want to create an "intermediate" function which takes a function name as an argument (along with a params array) and calls the appropriate function from a list of available static methods in a specific (predefined) set of classes. Like execute("someFunc",["one","two","three"]);.
Here's the full (test) code :
class Math {
static string noArgs(string[] s) { writeln(s); return ""; }
static string withOneArg(string[] s) { writeln(s); return ""; }
static string withTwoArgs(string[] s) { writeln(s); return ""; }
}
string cases()
{
string ret = "";
const string[] methods = [__traits(derivedMembers,Math)];
foreach (string s; methods)
{
ret ~= "case \"" ~ s ~ "\": return Math."~s~"(params);";
}
return ret;
}
string execute(string what, string[] params)
{
switch (what)
{
mixin(cases());
default: break;
}
return "";
}
The trouble with the above code is that it only looks for methods in Math. How could I change it, in an elegant D-friendly way, so that it'll go through an array of classes like [Math,String,SomethingElse] -- it doesn't have to be variable (we need it at compile-time anyway)?
UPDATE:
Tried something along the lines of :
const string[] methods = [__traits(derivedMembers,mixin("Math")];
but it complains that Cannot interpret Math at compile time.
UPDATE 2:
Also, tried using Object.factory("Math") but it's still not working. (Perhaps I'm just creating an instance of the Math class?)
Let me rewrite this to show you some cool tricks:
import std.stdio;
class Math {
static string noArgs(string[] s) { writeln(s); return ""; }
static string withOneArg(string[] s) { writeln(s); return ""; }
static string withTwoArgs(string[] s) { writeln(s); return ""; }
}
class String {
static string oneArg(string[] s) { return null; }
}
string execute(string what, string[] params) {
import std.string;
auto parts = what.split(".");
auto className = parts[0];
auto methodName = parts[1];
import std.typetuple;
switch(className) {
default: assert(0, "unknown class");
foreach(possibleClass; TypeTuple!(Math, String)) {
case possibleClass.stringof:
switch(methodName) {
default: assert(0, "unknown method");
foreach(memberName; __traits(derivedMembers, possibleClass)) {
case memberName:
return __traits(getMember, possibleClass, memberName)(params);
break;
}
}
break;
}
}
assert(0);
}
void main() {
execute("Math.withOneArg", ["cool"]);
execute("String.oneArg", ["cool"]);
}
Notice that there are no mixin expressions used at all. Instead of getting an instance of the class from a string, I just made a TypeTuple of all the classes I wanted to use. This is preferable to mixin because then it is less likely to find name classes when used in different scopes; if possibleClasses were a compile-time parameter to execute from a different module, the list of classes would still work, whereas the list of strings would see undefined identifier errors because the library module doesn't import your user module.
Another mixin I removed was the one to generate the cases. This looks insane, but is allowed in D: if you have a compile-time foreach (that is, a foreach over a built-in tuple of some sort, e.g. TypeTuple, template argument lists, the results of __traits...) you can actually put case statements inside them!
So, all you have to do is write a regular switch statement on the run time variable you want to compare against, put the foreach inside it looping over the compile-time stuff you're searching for, case that_loop_var: and boom, you're in business.
Similarly, I used __traits(getMember) rather than a mixin string to call the method. This solution will help avoid name clashes and IMO is cleaner code. It can also potentially handle overloads, if wanted (with __traits(getOverloads) instead of __traits(getMember), you can loop over each one then and match the parameter types).
Finally, nesting switches inside other case statements is allowed. If you need to break out of an outer loop or switch and don't want ambiguity, you can label loops and switches and use break label_name_here; to specify which one you want to break from. Ditto for continue with nested loops.
BTW you could also automatically generate the wrapper functions that convert string[] to other types of arguments if you dove into the std.traits stuff. I wish my book was out already, I wrote about this at some length in there and don't feel like writing it all right now but if you look at std.traits.ParameterTypeTuple and ReturnType in the same module that will get you started if you wanna try it.

Implementing TypeScript interface with bare function signature plus other fields

How do I write a class that implements this TypeScript interface (and keeps the TypeScript compiler happy):
interface MyInterface {
(): string;
text2(content: string);
}
I saw this related answer:
How to make a class implement a call signature in Typescript?
But that only works if the interface only has the bare function signature. It doesn't work if you have additional members (such as function text2) to be implemented.
A class cannot implement everything that is available in a typescript interface. Two prime examples are callable signatures and index operations e.g. : Implement an indexible interface
The reason is that an interface is primarily designed to describe anything that JavaScript objects can do. Therefore it needs to be really robust. A TypeScript class however is designed to represent specifically the prototype inheritance in a more OO conventional / easy to understand / easy to type way.
You can still create an object that follows that interface:
interface MyInterface {
(): string;
text2(content: string);
}
var MyType = ((): MyInterface=>{
var x:any = function():string { // Notice the any
return "Some string"; // Dummy implementation
}
x.text2 = function(content:string){
console.log(content); // Dummy implementation
}
return x;
}
);
There's an easy and type-safe way to do this with ES6's Object.assign:
const foo: MyInterface = Object.assign(
// Callable signature implementation
() => 'hi',
{
// Additional properties
text2(content) { /* ... */ }
}
)
Intersection types, which I don't think were available in TypeScript when this question was originally asked and answered, are the secret sauce to getting the typing right.
Here's an elaboration on the accepted answer.
As far as I know, the only way to implement a call-signature is to use a function/method. To implement the remaining members, just define them on this function. This might seem strange to developers coming from C# or Java, but I think it's normal in JavaScript.
In JavaScript, this would be simple because you can just define the function and then add the members. However, TypeScript's type system doesn't allow this because, in this example, Function doesn't define a text2 member.
So to achieve the result you want, you need to bypass the type system while you define the members on the function, and then you can cast the result to the interface type:
//A closure is used here to encapsulate the temporary untyped variable, "result".
var implementation = (() => {
//"any" type specified to bypass type system for next statement.
//Defines the implementation of the call signature.
var result: any = () => "Hello";
//Defines the implementation of the other member.
result.text2 = (content: string) => { };
//Converts the temporary variable to the interface type.
return <MyInterface>result;
})(); //Invokes the closure to produce the implementation
Note that you don't need to use a closure. You could just declare your temporary variable in the same scope as the resulting interface implementation. Another option is to name the closure function to improve readability.
Here's what I think is a more realistic example:
interface TextRetriever {
(): string;
Replace(text: string);
}
function makeInMemoryTextRetriever(initialText: string) {
var currentText = initialText;
var instance: any = () => currentText;
instance.Replace = (newText: string) => currentText = newText;
return <TextRetriever>instance;
}
var inMemoryTextRetriever = makeInMemoryTextRetriever("Hello");

How to parametrize my exports?

I'd like to be able to parametrize my exports not only with types (as in, generic exports), but also with values.
Something like:
class Greeter
{
readonly string _format;
public Greeter( string format ) { _format = format; }
public string Greet( string name ) { return string.Format( _format, name ); }
}
// ...
var e = new ExportProvider();
e.ExportParametrized<Greeter>( args: new[] { "Hi, {0}!" } );
e.ExportParametrized<Greeter>( args: new[] { "¡Hola, {0}!" } );
// And then:
[ImportMany] IEnumerable<Greeter> Greeters { get; set; }
foreach( var g in Greeters ) Console.WriteLine( g.Greet( "John" ) );
// Should print out:
// Hello, John!
// ¡Hola, John!
One might ask: why don't I simply export the value new Greeter( "Hello, {0}!" ) using ComposablePartExportProvider and CompositionBatch?
While this approach would work in this particular case, it has an important flaw: if the Greeter class had any imports of its own, they would not be satisfied.
The usual way I would go about this is to declare two classes - EnglishGreeter and SpanishGreeter, inherit them both from Greeter, and then provide the appropriate arguments in the call to base constructor.
But this doesn't work for two reasons:
This is a lot of noise to write. Not only do I have to type the whole shebang, I also have to come up with names for those classes, and it doesn't always make sense to have names. Not to mention the DRY principle. But even besides the noise...
Sometimes I don't know the parameters upfront. Say, for example, my greeting formats were coming from some kind of config file.
Here is another thought, to somewhat clarify what I'm looking for.
This problem is almost solved in the TypeCatalog. See, the TypeCatalog knows about the type and it calls the type's constructor to create the part on demand.
One can think of this process from another standpoint: the catalog has a factory function; using that function, it creates the part, then satisfies its non-prerequisite imports, and then returns the part back to the requestor.
Now, in the particular case of TypeCatalog, the factory function just happens to be the type's own constructor. If only I could hook in and replace the factory function with my own, but still leverage the rest of the machinery, that would be exactly what I'm looking for.
You can achieve this by using property exports. You could define a class specifically for those kinds of exports, and it will look like this:
class MyParameterizedExports
{
[Export(typeof(Greeter))]
private Greeter EnglishGreeter
{
get
{
Greeter g = new Greeter("Hi, {0}!");
container.SatisfyImportsOnce(g);
return g;
}
}
[Export(typeof(Greeter))]
private Greeter SpanishGreeter
{
get
{
Greeter g = new Greeter("¡Hola, {0}!");
container.SatisfyImportsOnce(g);
return g;
}
}
}
Here you export two separate Greeter instances without having to define a new class for each type of Greeter.