Func<T> Draft Proposal

Coordinator
Feb 3, 2010 at 9:50 AM

Hi,

I've uploaded a draft proposal for Func to the repository. So that everyone can take a quick look I've also uploaded it to the wiki as PDF here: http://cca.codeplex.com/Project/Download/FileDownload.aspx?DownloadId=104407

At this point feedback on the kind of information being gathered is very important.

I've also made some notes in the document describing the "levels of support" that we might use in a compatibility matrix.

Once we're relatively comfortable with Func we can look at the list of other adapters (including Func with parameters).

Nick

Feb 3, 2010 at 11:19 AM

Nick,

Can you elaborate this piece a bit: "If the components instantiated by the call to Func<T> require some kind of cleanup or decommission lifecycle then this remains the responsibility of the container or the infrastructure configuration."

 

My concern is, that delegates are a one way road, you can pull from them, but they do not address the issue of ending component' lifetime. Semantically this is not a concern of the user, but I can imagine this being used as factory for shortlived transient instances, that get pulled, used and discarded. Given the host component (one using the factory) has long lifespan it may create many such transient components. While it is not the responsibility of the caller to deal with lifecycle of the components it's using, they (directly or through their dependencies) may have decommission steps associated with them (like disposal).

This leads to following problem when using certain containers that do take care of this issue (namely Autofac and Windsor of these I've tried)

- as the container has no idea that the component is no longer used it is unable to perform its decommission keeping it alive for much longer than it needs to be (usually until the container itself gets disposed). This in turn may lead to memory issues.

I created sample solution that analyzes the behavior of most commonly used containers in this context here: http://github.com/kkozmic/IoCComponentBurden

 

Developer
Feb 3, 2010 at 9:19 PM

@kkozmic there are many possible ways to deal with this

- container transfer ownership in this case, so it doesn't need to keep instances (that limit the decommission lifecycle, but hey..who cares)

- instances are kept and child containers deal with shorter lifetimes (safest)

- Func<Owned<T>> allows the caller to "clean up"

I'm sure there are more.. just off the top of my head :-)

Feb 3, 2010 at 10:07 PM

@haveriss

Of course there are many ways to deal with this. However if we're striving for any consistency between containers, it should be addressed explicitly. Especially that, first of them is not Windsor's default behavior, so it requires additional step from user's perspective to set up, second one is the least invasive, but not very well advertised (which is a shame), and the third one adds additional layer of indirection, which can be solution to the issue, but it would also require explicit addressing.

Coordinator
Feb 3, 2010 at 11:42 PM

They're good points to have raised. Lifetime/Lifecycle are always thorny issues :)

The way I'm currently thinking about it is that the adapters are fine-grained and represent atomic units of a contract.

Func<T> says "I need to create instances" and by default those instances need to live as long as the caller. This is correct and works fine in many scenarios, e.g. when inside a unit of work (nested container), or when the caller really does need the instances for the rest of its lifetime.

Func<Owned<T>> adds more information to the contract. It says "I need to create instances, which I release at some point in the future".

The fact that Func<Owned<T>> is the right contract in many common scenarios probably suggests that it deserves an alias, e.g.

   delegate Owned<T> Factory<T>();

Worth considering, anyway... (This is roughly in line with MEF-for-Silverlight's PartCreator<T>.) Even using Windsor's TypedFactoryFacility, there is no mandatory requirement that Release be implemented. It is the same here - the contract has to be correct for the scenario.

Developer
Feb 4, 2010 at 2:35 AM

You could also say that Lazy<T> covers the case where the container giving you the instance is the one that will manage its lifecycle (either a long-lived container or a per-request one, doesn't matter), whereas Func<T> means you'll take care of it yourself. 

If my T happens to implement IDisposable (as it surely would if it needs any cleanup), then I'm done, right?

Coordinator
Feb 4, 2010 at 3:10 AM

Unfortunately not - T is probably an interface, which generally shouldn't be disposable. There's no way for the one defining an interface to foresee all possible implementations of it - you can always come up with a disposable implementation of practically any interface.

Even if you take a different approach and try to cast T to IDisposable, there's no way to a) know whether you're sharing the T with someone else, or b) make sure that all the dependencies of the T are appropriately cleaned up. A non-disposable T can always have disposable dependencies :)

Lazy<T> is a better fit for the case of lazy dependencies. There's already use of Func<T> for the same purpose on .NET 3.5 though. We might consider blessing "Lazy" as the one true lazy, but that scenario isn't really the tricky one here.

Coordinator
Feb 5, 2010 at 8:49 AM

Alright, with the benefit of some more time to think about it, how about this:

  1. We stipulate that the instances returned from the Func must live at least as long as the component calling the Func
  2. We remove the MessageHandler example and replace it with one reflecting this expectation
  3. We address the lifetime issue separately - either by composing something like "Owned" with Func, or by another proposal

I think the potential for real harm here is low.

  • Application developers unaware of the documented behaviour will still be familiar with both the components and more importantly the container they're using, and will configure working systems within those parameters (status quo)
  • Framework developers seeking true portability will be able to understand the spec and choose their adapters appropriately

I don't think we're going to "solve" the challenges that remain around lifetime in IoC here - containers are sharp tools. Let's not boil the ocean :)

Func is pretty much the most useful building block in describing contracts that include dynamic instantiation. Despite the drawbacks inherent in any dynamic instantiation mechanism, we can define a contract for Func that actually does work as intended in a wide variety of containers.

Unless there an alternative that we should be considering, Func seems like the way forward. Thoughts yay or nay?

Feb 5, 2010 at 12:20 PM

I agree completely that the container should be responsible for cleaning up the created instances, since having an abstraction derive from IDisposable is often a Leaky Abstraction.

However, I feel uneasy about the relationship with Lazy<B>. In my opinion, that is another Leaky Abstraction since the consumer can't really know whether or not the dependency is expensive to create or not. Even if this is the case, the issue can often be resolved by having a Singleton-scoped instance of the expensive dependency.

In any case, just saying that Func<T> exists and can be used as an Abstract Factory is in itself not particularly interesting. What becomes interesting is when consumers can request a dependency of type Func<IMyDep> and the container would supply the correct instance with the correct lifetime every time the Func is invoked. I'm guessing that this is the real purpose of this exercise, but perhaps we ought to be a bit more explicit about this?

Coordinator
Feb 6, 2010 at 9:02 PM

Mark, you're correct - we intend that Func<IMyDep> would resolve to dependencies on the concrete MyDep. I'll make an explicit note in the draft.

(I agree that we have some abstraction issues to work out around laziness - we should discuss that in more detail when we get to a laziness proposal. My suspicion is that a contract-centric rather than compoent-centric view is necessary here, i.e., the dependent component communicates "I only use this on some esoteric execution path" and whether or not that translates to a performance/resource usage benefit is dependent on the specific scenario the component is used in.)

Feb 8, 2010 at 1:12 PM

Basically, Func<T> is just a special case of an Abstract Factory. There may be cases where one would like an Abstract Factory to have more than one method, which Func<T> doesn't model, but I don't see how we could supply anything generic in that case...

(Let's have the discussion about laziness when we get to it, but expect me to disagree...)

Coordinator
Feb 13, 2010 at 10:24 AM

Sorry I am late to the show, will subscribe now to get the emails :-)

Func looks fine to me. Also as you mentioned it can easily support more explicit ownership through passing in an Owned<T> and having the func handle it as a special case. The parameter case Func<T, TParams> seems worth of considering as well.

Glenn

Coordinator
Feb 13, 2010 at 10:27 AM
Edited Feb 13, 2010 at 10:29 AM

An alternative way to possibly handle ownership would be supporting OwnedFunc<T>. This would be more explicit/discoverable and would remove the need for the special casing of Owned<T>. It could either return an Owned<T> or possibly return an IDisposable as an out ref. With Named params in C# that would work pretty nicely.

Glenn

Feb 21, 2010 at 10:33 PM

I really like this idea.

I think I'm partial to "Factory<>" over "Func<>" though.

Have you got any  code examples for this (independant of a container) that you can share?  I wouldn't mind playing around with this.

Coordinator
Feb 22, 2010 at 3:56 AM

At ALT.NET Seattle this weekend I convened a session on CCA. When it came to discussing factories a few folks reacted adversely to Func<T>, the reasoning being that it does not clearly express intent. A Func is not necessarily a factory thus it can be ambiguous. Lazy on the other hand has no amiguity. This argument convinced me that something more specific like Factory<T> or ComponentFactory<T> might be better.

Glenn

Coordinator
Feb 22, 2010 at 9:30 AM

Would Factory<T,...> be a set of delegate types with the signatures equivalent to Func<>?

Sounds like a worthwhile change- expressing intent clearly is good.

Does anyone foresee issues with this? If there's a general agreement I'll update the proposal.

Nick

Feb 22, 2010 at 12:03 PM

Func<> has the obvious advantage that it's in the BCL

If we choose not to go with it, do we then provide one single canonical generic set of delegates, like Func<> or do we broaden the semantics to just any kind of delegate, so that users can have:

public delegate IMessageHandler MessageHandlerFactory();
in their domain and use that as container-backed factory as well?

 

Developer
Feb 22, 2010 at 1:54 PM
I'd rather go with the BCL Func, but I realize that sooner or later we'll have to introduce canonical types anyway (i.e. Owned<T> or whatever), so fighting this might not be worth it.

What I like about Func<T> is that by not being explicit, it allows the flexibility I might actually need (i.e. turning a component from a single-call to a singleton just via configuration as I see fit). If it's called Factory<T> then it sounds to me that I'm saying I always want a new one (factories *create* things, not merely access them if they are already created).

/kzu

--
Daniel Cazzulino | Developer Lead | XML MVP | Clarius Consulting | +1 425.329.3471


On Mon, Feb 22, 2010 at 10:03, kkozmic <notifications@codeplex.com> wrote:

From: kkozmic

Func<> has the obvious advantage that it's in the BCL

If we choose not to go with it, do we then provide one single canonical generic set of delegates, like Func<> or do we broaden the semantics to just any kind of delegate, so that users can have:

public delegate IMessageHandler MessageHandlerFactory();
in their domain and use that as container-backed factory as well?

 

Read the full discussion online.

To add a post to this discussion, reply to this email (cca@discussions.codeplex.com)

To start a new discussion for this project, email cca@discussions.codeplex.com

You are receiving this email because you subscribed to this discussion on CodePlex. You can unsubscribe or change your settings on codePlex.com.

Please note: Images and attachments will be removed from emails. Any posts to this discussion will also be available online at codeplex.com


Feb 22, 2010 at 3:12 PM
dcazzulino wrote:
I'd rather go with the BCL Func, but I realize that sooner or later we'll have to introduce canonical types anyway (i.e. Owned<T> or whatever), so fighting this might not be worth it.
What I like about Func<T> is that by not being explicit, it allows the flexibility I might actually need (i.e. turning a component from a single-call to a singleton just via configuration as I see fit). If it's called Factory<T> then it sounds to me that I'm saying I always want a new one (factories *create* things, not merely access them if they are already created).

The draft details that it should be a Factory anyway.  Using "Factory<T>" would make it more clear  Having an explicit type also makes it easier to go towards the convention over configuration model.  For example, "Func<Order>" could mean anything; "Factory<Order>" is really focused.  My container could could know how to create Order objects and automatically inject where Factory<Order> appears.  Func<Order> would have to be configured everywhere it's used.

Feb 22, 2010 at 7:54 PM

I must admit that the whole purpose of this discussion still eludes me (and I really mean it - I'm not being sarcastic).

A delegate is really just an anonymous interface, so a Func is equivalent to an anonymous Abstract Factory. That's a pretty normal thing to inject into a consuming class, so something like this should come as no surprise:

public class MyClass
{
    private readonly Func<IDep> f;

    public MyClass(Func<IDep> f)
    {
        // Insert Guard Clause here
        this.f = f;
    }

    public void DoStuff()
    {
        var dep = this.f();
        dep.Foo("bar");
    }
}

What I really don't understand is what we gain by declaring that we can use a Func as an Abstract Factory. Yes, of course we can do that, from a pure DI perspective. My litmus test is always whether it's possible to express it with Poor Man's DI, and using a Func in this way passes with flying colors.

I don't, however, understand how this can in any way serve as an adapter. Those containers that already understand delegates can already support this idiom, and those that don't will still not support it.

So what do we gain from explicitly declaring that a Func is, indeed, an Abstract Factory?

Coordinator
Feb 22, 2010 at 9:07 PM
nblumhardt wrote:

Would Factory<T,...> be a set of delegate types with the signatures equivalent to Func<>?

Sounds like a worthwhile change- expressing intent clearly is good.

Does anyone foresee issues with this? If there's a general agreement I'll update the proposal.

Nick

 Yes, it would be identical to the Func<> only more explicit as to the expected behavior.

Coordinator
Feb 22, 2010 at 11:01 PM

@ploeh, there are a few variations on how Func<...> can be interpreted, even as an Abstract Factory. Philip for example suggested that Func<string, T> would use the first argument as the component's key, while the same parameter will be treated as a constructor argument in Autofac and Windsor (with experimental LightweightFactoryFacility.)

This whole project isn't very broad in scope, so your observation that it isn't such a big deal is correct :)  ... Getting all of these little things (like the meaning of params, ownership transfer semantics etc) consistent is feasible now while the approach doesn't have very wide adoption.

Feb 23, 2010 at 6:36 AM

Yeah, I don't see a problem with Func<T> compared to Factory<T>... In Linq the extension methods take Func<T,bool> predicate and selector instead of Predicate<T, bool>, etc.

Also, for unit testing, would it be as easy to pass a lambda into a Factory<T> ctor argument as it would be to pass ()=>t to a Func<T>?

The idea of a selector parameter to Func is really interesting. Is there a way that would be a metadata <M,bool> selector ?

 

Func<Func<M,bool>,IDep> _depFactory;
...
var xdep = _depFactory(m=>m.Prop==x);
var ydep = _depFactory(m=>m.Prop==y);

 

(Of course, that could be too confusing, or I could misunderstand the meaning Meta since I haven't caught up on the concepts.)

 

Feb 23, 2010 at 8:05 AM

Thanks for clearing up some of my confusion.

As I have already hinted in the discussion about Optional<T>, I find it paramount that abstractions and API design are DI Friendly, but essential Container-unaware. I've always found named instances (container keys) a Leaky Abstraction because they leak out that there's a DI Container in play. In that light, I would strongly argue that Func<string, IMyDep> indicates an Abstract Factory that maps a string to an IMyDep instance. Conceptually, it is no different than Func<int, IMyDep> or Func<IMyValue, IMyDep>.

Feb 23, 2010 at 3:58 PM
loudej wrote:

Yeah, I don't see a problem with Func<T> compared to Factory<T>... In Linq the extension methods take Func<T,bool> predicate and selector instead of Predicate<T, bool>, etc.

Also, for unit testing, would it be as easy to pass a lambda into a Factory<T> ctor argument as it would be to pass ()=>t to a Func<T>?

The idea of a selector parameter to Func is really interesting. Is there a way that would be a metadata <M,bool> selector ?

 

Func<Func<M,bool>,IDep> _depFactory;
...
var xdep = _depFactory(m=>m.Prop==x);
var ydep = _depFactory(m=>m.Prop==y);

 

(Of course, that could be too confusing, or I could misunderstand the meaning Meta since I haven't caught up on the concepts.)

 

Yes, the difference in Func and Factory is just the name in terms of their ability to be "assigned" by method group.

Feb 23, 2010 at 4:01 PM

I don't know all the impetus' that are driving CCA (or if there's more than one :).  But, Glenn described the need for less of a dependency on the Common Service Locator (CSL) at ALT.NET Seattle.  This is what I get out of that (I don't want to put words into Glenn's mouth):  The CSL was a great innovation in that it allowed the abstraction away from a particular container (after all, managing dependencies is the point of the container, right?).  The problem became that CSL easily became the factory throughout the code base.  Sure, this is a "better" dependency that directly on the container; but it really didn't provide an intuitive way to be loosly coupled from the CSL.

Enter CCA.  What CCA is proposing is a set of decoupled abstractions.  The benefit of this is that there's a series of conventions for implementing a factory.  CSL was an abstraction for the container and got "misused" as a factory.  What the CCA abstractions will do is provide programmers guidance on supporting factories.  This, of course, is completely decoupled from anything else, CSL, IoC containers, project-specific factories, etc. etc.

Of course, once you pull in the idea of a factory, you then need to pull in the idea of lifetimes and whether dependencies are optional or not.

CCA will give designers and programmers a way to define factory dependencies independently of IoC container or CSL.  Both CSL and the container become implementation details more easily.

There's all sorts of other benefits to what CCA is proposing like delegates over interfaces, etc. etc.

What I like about what's defined so far (assuming Factory<T>, not Func<T>) is it provides a distinct convention; so, a container can automatically wire up c'tor arguments and properties based on their type, not on specific configuration.

Cheers -- Peter

Coordinator
Feb 23, 2010 at 4:06 PM

It's more than just the signature, it is about expressing intent. Factory is very clear what it is expected to do. Func returns a value yes, but it does not imply anything about how that func operates.

Glenn

Feb 23, 2010 at 4:18 PM
gblock wrote:

It's more than just the signature, it is about expressing intent. Factory is very clear what it is expected to do. Func returns a value yes, but it does not imply anything about how that func operates.

Glenn

I think one concern the Func over Factory folks have is it's difficulty to be used where a Func<T> is expected.  This is a valid concern; but, I don't see much need for that ability where Func<T> is used in the BCL/CLR.

Coordinator
Feb 23, 2010 at 11:50 PM

So assuming we went forward with Factory<T>, would it be required that the returned instances of T would be unique?

I can see pros/cons either way, and don't have much of an opinion on it...

Nick

Coordinator
Feb 24, 2010 at 12:05 AM

I'd argue yes. The implication would be you take ownership of the lifetime of the object once you call it.

Glenn

Feb 24, 2010 at 8:09 AM

I think that the implication that Factory<T> returns unique instances would be faulty.

An Abstract Factory doesn't necessarily imply that new instances are created every time they are invoked. They may for example also be used in Decorators for deferred loading.

However, this becomes even more apparent when the Abstract Factory takes one or more arguments. In such cases the factory may be serve more as a mapping than a creational pattern.

Consider a message handling system where we have different message handlers (IMessageHandler) for different types of messages (IMessage). When a message arrives, we want to use the appropriate IMessageHandler to handle the message, and we can use an Abstract Factory for that:

private readonly Factory<IMessage, IMessageHandler> f;

public IReply Receive(IMessage msg)
{
    IMessageHandler handler = this.f(msg);
    return handler.ReplyTo(msg);
}

The point is that there may only be one instance of each IMessageHandler type, so the factory is just a Map.

If those concrete IMessageHandler implementations are expensive to create, I'd certainly prefer to just keep a dozen of those around in memory and serve the correct one each time it's requested, instead of creating new instances every time.

Another issue could be that those IMessageHandlers may contain state (perhaps in the form of an in-memory cache) so implying that a new instance should always be created severely limits the options we have.

The factory (and by implication: the container) should manage the lifetime of the created instance.

Coordinator
Feb 24, 2010 at 8:24 AM

Why not simply use a Message Handler Service for that as opposed to the factory? My understanding of why the factory is needed is to allow creating new instances on the container which automatically have their dependencies resolved, something that you cannot do easily today. Having a service that simply contains a dictionary and maps message types to handlers seems pretty trival to do. Are you thinking that he container knows how to build this map?

Regards

Glenn

Feb 24, 2010 at 8:53 AM

As always, trivial examples tend to be too trivial, but if you make them sufficiently complex then no-one bothers to read them :/

You are right that if you take my example at face value, a single MessageHandlerService would suffice. However, there are defintely cases where the return value of a call to an Abstract Factory is a cental domain concept that we need to deal with in a more complex manner. Imagine that we need to pass the handler instance around instead of just invoking and ditching it right away.

I'm not saying that it's always like this - I'm just saying that I don't like having my options constrained.

If we say that Factory<T> implies a unique instance every time, I can't elect to have it any other way.

If, on the other hand, we say that it's up to the implementer, we can still create implementations where it serves up a new instance every time, but we can also configure the implementation to reuse instances if we rather need to do that.

Coordinator
Feb 24, 2010 at 9:40 AM

It's possible I am worrying for nothing. The fear is somehow this gets used as a Service locator :-)

Feb 24, 2010 at 10:29 AM

Oh, we actually agree on something :)

That's a danger, but I don't know how we can address this in any other way than by guidance.

The problem wiith Func<T>, Factory<T> (or even IFactory<T>) is that the generic type is structurally identical to a Service Locator. However, any constructed Factory<T> isn't.

This constructor demonstrates an abstract Service Locator in action:

public MyClass(Factory<T> f) {}

This other constructor, however, simply requests an Abstract Factory:

public MyClass(Factory<IFoo> f) {}

The first example is an anti-pattern, the second is often a very appropriate thing to do.

Feb 24, 2010 at 5:46 PM

I agree with Glenn, Factory patterns are almost always categorized as creational patterns.  Caching may be important to many systems; but separating that out from creational would add value in much the same way as Owned<T> does.

Feb 24, 2010 at 5:52 PM
+1

If I need a factory I would prefer that the dependency I am taking be explicit. Sure, the implementing container could violate the Liskov Substitution Principle and hand out existing instances from a Factory<T>, as if it were a service locator, but there are ways around having to do this, for instance (pun intended) returning new instances of proxies or adapters that delegate to the existing "cached" instances. If you don't expect your dependency to act like a factory, then just use a delegate type with a different name and contract. If you need a delegate dependency to resolve different existing instances based on some context you pass in to it, then you probably ought to use a service to do the resolving for you instead of relying on the container.

As a side note, what do you all think about specifying a convention that any delegate type having a return value and a name ending in "Factory" would be resolved as a factory. This way a framework can have named delegate types with named parameters, the benefit I foresee of this is that the intention for the semantics of any parameters for the factory delegate could be made a little more visible. What should one expect the input parameters for Factory<int, int, int, IResource>() to mean?

On Wed, Feb 24, 2010 at 10:46 AM, ritchiep <notifications@codeplex.com> wrote:

From: ritchiep

I agree with Glenn, Factory patterns are almost always categorized as creational patterns.  Caching may be important to many systems; but separating that out from creational would add value in much the same way as Owned<T> does.

Read the full discussion online.

To add a post to this discussion, reply to this email (cca@discussions.codeplex.com)

To start a new discussion for this project, email cca@discussions.codeplex.com

You are receiving this email because you subscribed to this discussion on CodePlex. You can unsubscribe or change your settings on codePlex.com.

Please note: Images and attachments will be removed from emails. Any posts to this discussion will also be available online at codeplex.com


Developer
Feb 24, 2010 at 6:12 PM
So (and I know I may be getting ahead of the discussion on Lazy<T>), if you want to get an instance of a T but you don't care if it's created new everytime or cached/singleton, how would you express it?

Sounds like leaving this responsibility to the consumer of the T is essentially fixing a decision that is not his to make. For all that matters, it could depend on the actual implementation of the dependency whether it can be reused or not. There should be an easy way of allowing this flexibility.

Initially, my thinking was that you'd use a Func<T> to get a new one every time, and a Lazy<T> to get the same one (after the first lazy-instantiation), but now I'm not convinced this is the best way either...

Could it be that this is also related to Owned<T>? If I'm getting a new instance every time, then I own its lifetime (as glenn mentioned), right? By opposition, getting a Lazy<T> might imply I don't own it?

/kzu

--
Daniel Cazzulino | Developer Lead | XML MVP | Clarius Consulting | +1 425.329.3471


On Wed, Feb 24, 2010 at 15:46, ritchiep <notifications@codeplex.com> wrote:

From: ritchiep

I agree with Glenn, Factory patterns are almost always categorized as creational patterns.  Caching may be important to many systems; but separating that out from creational would add value in much the same way as Owned<T> does.

Read the full discussion online.

To add a post to this discussion, reply to this email (cca@discussions.codeplex.com)

To start a new discussion for this project, email cca@discussions.codeplex.com

You are receiving this email because you subscribed to this discussion on CodePlex. You can unsubscribe or change your settings on codePlex.com.

Please note: Images and attachments will be removed from emails. Any posts to this discussion will also be available online at codeplex.com


Feb 24, 2010 at 6:30 PM

In my book, one of the many benefits of DI is that we separate dependencies' lifetimes from their consumers. This gives us the flexibility we need.

We may have one concrete implementation of a dependency that works best with a certain lifetime style (say, Ephemeral/Transient/whatever), while a different implementation (of the same interface) works best with another (e.g. Singleton).

We may also have different applications using the same object model where we would very much like the lifetimes to be different, even if we are using the same implementation. As an example, a web application typically have quite different lifestyle requirements (PerWebRequest) than rich clients (which may benefit from Singletons). However, such applications may still share some of their code bases.

The strength of DI is that we can defer the lifetime decision until the Last Responsible Moment. Having a decree that dictates that we can't do that takes away that flexibility and severely amputates the benefits of DI.

Feb 24, 2010 at 6:54 PM
ploeh wrote:

In my book, one of the many benefits of DI is that we separate dependencies' lifetimes from their consumers. This gives us the flexibility we need.

We may have one concrete implementation of a dependency that works best with a certain lifetime style (say, Ephemeral/Transient/whatever), while a different implementation (of the same interface) works best with another (e.g. Singleton).

We may also have different applications using the same object model where we would very much like the lifetimes to be different, even if we are using the same implementation. As an example, a web application typically have quite different lifestyle requirements (PerWebRequest) than rich clients (which may benefit from Singletons). However, such applications may still share some of their code bases.

The strength of DI is that we can defer the lifetime decision until the Last Responsible Moment. Having a decree that dictates that we can't do that takes away that flexibility and severely amputates the benefits of DI.

I entirely agree with that.  But, when a class takes on the responsibility of managing the creation (and thus the lifetime style) by taking a dependency upon a factory (e.g. Factory<T> or Func<T>) all that pretty much goes out the window.  It would be fine to say that Factory<Order> *could* be caching, or it could send back a lazy instance; but, then it doesn't know the context in which the object is being retreived; and thus its most certainly not their responsibility to do so.  You could loosen the coupling even further by using an abstract factory like Factory<IOrder> but the container is still taking on the responsibility of creation and thus is the only class that can take on the responsibility of lifetime.  e.g. public class MyClass { public MyClass(Factory<IOrder> orderFactory) {/*...*/}}

If the class didn't take on the creation responsibility e.g. publc class MyClass { public MyClass(IOrder newOrder) {/*...*/}} then the container could decide; because only then can it associate the lifetime of both objects together.  But, even in this example, how could the container make a decision whether to use a cached open or create a new object solely on the information it has?  Based on the name of the c'tor argument, it's expecting a new IOrder; but how would the container know that.  At some point the containing class needs to project its need (and thus again take responsibility) of lifetime style.

 

Feb 24, 2010 at 7:08 PM

For some time now, I've had the feeling that we were talking about slightly different things, but I couldn't really nail what it was. Now I think I know.

I understand what you are saying about factory as a creational pattern. However, my perspective is slightly different:

I consider Func<T> to simply be a degenerate case of Func<T, TResult>, Func<T1, T2, TResult> etc. Those other variations on Abstract Factory are much more interesting than the degenerate case because they can be used to bridge objects known only at run-time with dependencies defined at start-up time (here's an example). In fact, while I use such factories all the time, I'm having a hard time coming up with a valid scenario for the degenerate case. I'm almost inclined to call it a code smell if you take a dependency on a parameterless factory, because why didn't you just take a dependency on the abstraction directly? Why do you want to explictly control the lifetime?

I'm sure that there are valid scenarios - I just can't think of any :)

However, when it comes to factories with parameters they might just as well be mappings rather than true factories.

Coordinator
Feb 24, 2010 at 8:56 PM

Good discussion so far, a few points I think I can add:

  • Allowing the factory to return the same instance multiple times doesn't limit behaviour in any significant way, while adding the "no caching restriction" does, so perhaps the the best choice is to not make the restriction, and leave that decision up to the container/configuration
  • In either case, we can't do ownership transfer with Factory<T..> because of the transient dependency release problem - perhaps another point in leaving lifetime in this scenario up to the container/config, and discuss this more in relation to Owned<T>
  • The parameterless Factory<T> does have at least one valid scenario when combined with metadata, i.e. Meta<Func<IHandler>, IHandlerMetadata>, but I agree it makes little sense to consider it in isolation to the parameterised versions

It seems like we have a fairly broad understanding of the task now, and a good range of perspectives being brought to the table.

I'd like to update the proposal with:

  • Factory<T> instead of Func<T>
  • Parameterisation included (no more separation of parameterised/parameterless versions, although we still might assess container support separately)
  • No change to the ownership transfer semantics
  • No requirement that returned instance are unique

Unless I've misinterpreted the general sentiment (as always correct me if I'm wrong,) this seems like the safest path.

Nick

Coordinator
Feb 24, 2010 at 11:39 PM
ploeh wrote:

For some time now, I've had the feeling that we were talking about slightly different things, but I couldn't really nail what it was. Now I think I know.

I understand what you are saying about factory as a creational pattern. However, my perspective is slightly different:

I consider Func<T> to simply be a degenerate case of Func<T, TResult>, Func<T1, T2, TResult> etc. Those other variations on Abstract Factory are much more interesting than the degenerate case because they can be used to bridge objects known only at run-time with dependencies defined at start-up time (here's an example). In fact, while I use such factories all the time, I'm having a hard time coming up with a valid scenario for the degenerate case. I'm almost inclined to call it a code smell if you take a dependency on a parameterless factory, because why didn't you just take a dependency on the abstraction directly? Why do you want to explictly control the lifetime?

I'm sure that there are valid scenarios - I just can't think of any :)

However, when it comes to factories with parameters they might just as well be mappings rather than true factories.

The scenario for creation occurs usually in response to a user action / or event. Here's two concrete scenarios. The first one I have ran into personally many times.

1. An order management system allows you to work with multiple orders at one time. Each time a user clicks to create an order or open an existing, an order screen is added. That order screen has it's own view model which uses various services. The OrderController will utilize a factory such as we are describing to create the new order screens on demand.

2. Your message handler scenario. A new message is received and at the time of it's receipt a new handler instance is created based on the message type. The factory creates the message handler injecting all of it's dependencies.s

Gelnn

Coordinator
Feb 24, 2010 at 11:40 PM

I am not seeing why would not enfroce that it be unique. It seems like not doing that is paving the way to ambiguities and abuses.

Feb 25, 2010 at 6:23 AM

@gblock

This seem like an artificial restriction to me, and unnecessary one. What value does it bring? I Do agree than Lazy<T> should be used for unique value, but first - we target not only .NET 4.0, and  We might want to use version with parameters.

This brings an entire set of valid scenarios. For example, using Func<TMessage,THandler> using semantics of StructureMap's ConnectImplementationsToTypesClosing. We would have our factory return a set of singletons.

 

Coordinator
Feb 25, 2010 at 8:37 AM

My whole reason for pushing Factory<T> was to express intent / set expectations for the caller as Robert mentioned. If we're saying that Factory<T> really is not constrained by manufactoring new instances, I'd "almost" say that Func<T> is fine then.

Glenn

Feb 25, 2010 at 9:00 AM
gblock wrote:
ploeh wrote:

For some time now, I've had the feeling that we were talking about slightly different things, but I couldn't really nail what it was. Now I think I know.

I understand what you are saying about factory as a creational pattern. However, my perspective is slightly different:

I consider Func<T> to simply be a degenerate case of Func<T, TResult>, Func<T1, T2, TResult> etc. Those other variations on Abstract Factory are much more interesting than the degenerate case because they can be used to bridge objects known only at run-time with dependencies defined at start-up time (here's an example). In fact, while I use such factories all the time, I'm having a hard time coming up with a valid scenario for the degenerate case. I'm almost inclined to call it a code smell if you take a dependency on a parameterless factory, because why didn't you just take a dependency on the abstraction directly? Why do you want to explictly control the lifetime?

I'm sure that there are valid scenarios - I just can't think of any :)

However, when it comes to factories with parameters they might just as well be mappings rather than true factories.

The scenario for creation occurs usually in response to a user action / or event. Here's two concrete scenarios. The first one I have ran into personally many times.

1. An order management system allows you to work with multiple orders at one time. Each time a user clicks to create an order or open an existing, an order screen is added. That order screen has it's own view model which uses various services. The OrderController will utilize a factory such as we are describing to create the new order screens on demand.

2. Your message handler scenario. A new message is received and at the time of it's receipt a new handler instance is created based on the message type. The factory creates the message handler injecting all of it's dependencies.s

Gelnn

Thanks for providing examples, but aren't these still factories with parameters? I'd think that the second example definitely is (as I originally described it). I've used Abstract Factory lots of times myself when it comes to create new Views, but normally I'd pass a ViewModel to the factory, so once again I think that this does't give me a lot of ideas about when the parameterless factory would be warranted.

Coordinator
Feb 25, 2010 at 9:12 AM
ploeh wrote:
gblock wrote:
ploeh wrote:

For some time now, I've had the feeling that we were talking about slightly different things, but I couldn't really nail what it was. Now I think I know.

I understand what you are saying about factory as a creational pattern. However, my perspective is slightly different:

I consider Func<T> to simply be a degenerate case of Func<T, TResult>, Func<T1, T2, TResult> etc. Those other variations on Abstract Factory are much more interesting than the degenerate case because they can be used to bridge objects known only at run-time with dependencies defined at start-up time (here's an example). In fact, while I use such factories all the time, I'm having a hard time coming up with a valid scenario for the degenerate case. I'm almost inclined to call it a code smell if you take a dependency on a parameterless factory, because why didn't you just take a dependency on the abstraction directly? Why do you want to explictly control the lifetime?

I'm sure that there are valid scenarios - I just can't think of any :)

However, when it comes to factories with parameters they might just as well be mappings rather than true factories.

The scenario for creation occurs usually in response to a user action / or event. Here's two concrete scenarios. The first one I have ran into personally many times.

1. An order management system allows you to work with multiple orders at one time. Each time a user clicks to create an order or open an existing, an order screen is added. That order screen has it's own view model which uses various services. The OrderController will utilize a factory such as we are describing to create the new order screens on demand.

2. Your message handler scenario. A new message is received and at the time of it's receipt a new handler instance is created based on the message type. The factory creates the message handler injecting all of it's dependencies.s

Gelnn

Thanks for providing examples, but aren't these still factories with parameters? I'd think that the second example definitely is (as I originally described it). I've used Abstract Factory lots of times myself when it comes to create new Views, but normally I'd pass a ViewModel to the factory, so once again I think that this does't give me a lot of ideas about when the parameterless factory would be warranted.

Not necessarily parameters. The message case yes, the ViewModel case not necessarily. But regardless I thought your question was why do we need to create new instances which is what my examples were discussing. Now I am confused.

Developer
Feb 25, 2010 at 11:41 AM
that was my entire point too. 
if we're not mandating that it constructs new instances everytime, it's not a factory-proper. We should leave it as Func then.

/kzu

--
Daniel Cazzulino | Developer Lead | XML MVP | Clarius Consulting | +1 425.329.3471


On Thu, Feb 25, 2010 at 06:37, gblock <notifications@codeplex.com> wrote:

From: gblock

My whole reason for pushing Factory<T> was to express intent / set expectations for the caller as Robert mentioned. If we're saying that Factory<T> really is not constrained by manufactoring new instances, I'd "almost" say that Func<T> is fine then.

Glenn

Read the full discussion online.

To add a post to this discussion, reply to this email (cca@discussions.codeplex.com)

To start a new discussion for this project, email cca@discussions.codeplex.com

You are receiving this email because you subscribed to this discussion on CodePlex. You can unsubscribe or change your settings on codePlex.com.

Please note: Images and attachments will be removed from emails. Any posts to this discussion will also be available online at codeplex.com


Feb 25, 2010 at 12:05 PM

Func<T> has the appearance of lack of focus.  To newcomers it will be confusing "What do I need to pass for a Func<T>".

As much as I agree that the method/class that uses the delegate shouldn't have the responsibility of object lifetime; it's the only thing that has requirements that affect lifetime.  If a method *needs* new instances every time, how does it communicate that to whatever is injecting the delegate?  With Func<T> it would require some configuration.  With the convention Factory<T>, and the understanding that it's a Factory proper (creational pattern) then it simply needs to tell consumers of its interface that it needs Factory<T>.

I'm not saying that's the only delegate that returns objects that may be required; but it's certainly going to be a very common case.

Feb 25, 2010 at 1:56 PM
ritchiep wrote:

Func<T> has the appearance of lack of focus.

And that's the beauty of it. Let us not loose focus of this whole endeavor - provide viable alternative to service locator - one that is flexible enough to be used in many scenarios.

With Func<T> due to it's lack of strong semantics we can use it in many contexts. With Factory<T>, we'd soon need MetaInstance<T> or InstanceProvider... then when we introduce 2nd generic parameter we're up for exponentially growing number of abstractions we'd need to cover every scenario this way. What's the point?

I rarely see an actual need of user code to depend on fact whether it receives new instance each time it requests an instance, whether there's a pool, or a singleton. I'm happy leaving that up to the container configuration part. In fact every time I do see such need, I find it more suitable to use Owned in the first place.

And let's not try to shield users from themselves. I think piece of guidance is more than enough for that.

Feb 25, 2010 at 3:49 PM
kkozmic wrote:
ritchiep wrote:

Func<T> has the appearance of lack of focus.

And that's the beauty of it. Let us not loose focus of this whole endeavor - provide viable alternative to service locator - one that is flexible enough to be used in many scenarios.

With Func<T> due to it's lack of strong semantics we can use it in many contexts. With Factory<T>, we'd soon need MetaInstance<T> or InstanceProvider... then when we introduce 2nd generic parameter we're up for exponentially growing number of abstractions we'd need to cover every scenario this way. What's the point?

I rarely see an actual need of user code to depend on fact whether it receives new instance each time it requests an instance, whether there's a pool, or a singleton. I'm happy leaving that up to the container configuration part. In fact every time I do see such need, I find it more suitable to use Owned in the first place.

And let's not try to shield users from themselves. I think piece of guidance is more than enough for that.

But, without any focus, doesn't Func<T> just become it's lowest common denominator: another Service Locator? (at least when used with abstractions--and as Mark pointed out, what's the point of using it without abstractions)  If it's not a factory, and it's not a pool, and it's not a queue, what is it?  If it's not clear it's rife for the same abuse CCA seems to be trying to address with regard to CSL...

I agree that isn't always the need for a new instance.  Some lifetime styles can be defined on the class/interface that defines it (like a singleton; there's never a need for a consumer of a class to know/care/need an implementation to be a singleton--regardless of my view that singleton is a code smell).  It's the times that only the consumer really knows that it always needs a new instance that throws a wrench in the works.

Of course, it probably may depend on what *our* definition of things like pool are.  For the most part, the CLR has really good memory management and a pool of discarded but re-usable objects may actually be detrimental to performance.

Maybe I'm reading too much into the proposal; but the more abstract we get with it the more it seems that, as you say, mere guidance is a enough.  i.e. what does the convention of using Func<T> buy anyone?  It's not like the Factory pattern or object pools hasn't been around for years.  The pattern guidance didn't help anyone misuse CSL; why should we expect any other guidance to be better.

What is CCA if not just more guidance?

Developer
Feb 25, 2010 at 5:11 PM
So, given this (converging?) consensus on flexibility, I think we'd need to provide guidance on how various containers implement instance creation by default for these Funcs, right? 

Maybe a sensible default could be specified and the various containers could somehow switch to "CCA Compliant Mode" by changing their defaults appropriately?

/kzu

--
Daniel Cazzulino | Developer Lead | XML MVP | Clarius Consulting | +1 425.329.3471


On Thu, Feb 25, 2010 at 13:17, kkozmic <notifications@codeplex.com> wrote:

From: kkozmic

ritchiep wrote:

Func<T> has the appearance of lack of focus.

And that's the beauty of it. Let us not loose focus of this whole endeavor - provide viable alternative to service locator - one that is flexible enough to be used in many scenarios.

With Func<T> due to it's lack of strong semantics we can use it in many contexts. With Factory<T>, we'd soon need MetaInstance<T> or InstanceProvider... then when we introduce 2nd generic parameter we're up for exponentially growing number of abstractions we'd need to cover every scenario this way. What's the point?

I rarely see an actual need of user code to depend on fact whether it receives new instance each time it requests an instance, whether there's a pool, or a singleton. I'm happy leaving that up to the container configuration part. In fact every time I do see such need, I find it more suitable to use Owned in the first place.

And let's not try to shield users from themselves. I think piece of guidance is more than enough for that.

Read the full discussion online.

To add a post to this discussion, reply to this email (cca@discussions.codeplex.com)

To start a new discussion for this project, email cca@discussions.codeplex.com

You are receiving this email because you subscribed to this discussion on CodePlex. You can unsubscribe or change your settings on codePlex.com.

Please note: Images and attachments will be removed from emails. Any posts to this discussion will also be available online at codeplex.com


Feb 25, 2010 at 5:21 PM
Well even if we Factory<T> advocates concede your points, I still think that the semantics of the behavior you are expecting ought to be considered when choosing a name. Given this, I still think Func is deficient, e.g. unnecessarily vague. What would you think about Locate or maybe Resolve? My rational is that Factory, Locate and Resolve might be considered functions but not all functions do construction, location or resolution. Some functions just do calculations. The vagueness of Func is fine for use cases such as with LINQ, but my impression was that, in order to avoid having IServiceLocator sprinkled everywhere, one of the key goals for this endeavor was to provide a standard set of types that would provide more expressive dependency semantics for containers to resolve dependencies with. Perhaps we ought to distill these different use cases where we might prefer a Func over a Factory and then provide delegates to better express the semantics for each use case?

I can think of places in my code that I want a new instance from the container each time and I'd like to tell it this, hence I would like a Factory. These instances I'm getting from the container are supposed to be mutable and transient and so I am certain I don't want to simply "resolve" or "locate", and I'm more than certain I don't want to "Func". And like I said before, if the container for some reason can't or doesn't want to create new instances each time it can create proxies or adapters that delegate to the cached instance and still not violate LSP. So I don't see a problem with more explicit dependency semantics for lifetime, construction location, etc. because sometimes the consumer cares about these things, and when it does then let the container bend the rules a little if it has to in order to conform to these semantics, but if you think Factory is a smell, then just don't use it.


On Thu, Feb 25, 2010 at 8:17 AM, kkozmic <notifications@codeplex.com> wrote:

From: kkozmic

ritchiep wrote:

Func<T> has the appearance of lack of focus.

And that's the beauty of it. Let us not loose focus of this whole endeavor - provide viable alternative to service locator - one that is flexible enough to be used in many scenarios.

With Func<T> due to it's lack of strong semantics we can use it in many contexts. With Factory<T>, we'd soon need MetaInstance<T> or InstanceProvider... then when we introduce 2nd generic parameter we're up for exponentially growing number of abstractions we'd need to cover every scenario this way. What's the point?

I rarely see an actual need of user code to depend on fact whether it receives new instance each time it requests an instance, whether there's a pool, or a singleton. I'm happy leaving that up to the container configuration part. In fact every time I do see such need, I find it more suitable to use Owned in the first place.

And let's not try to shield users from themselves. I think piece of guidance is more than enough for that.

Read the full discussion online.

To add a post to this discussion, reply to this email (cca@discussions.codeplex.com)

To start a new discussion for this project, email cca@discussions.codeplex.com

You are receiving this email because you subscribed to this discussion on CodePlex. You can unsubscribe or change your settings on codePlex.com.

Please note: Images and attachments will be removed from emails. Any posts to this discussion will also be available online at codeplex.com


Coordinator
Feb 27, 2010 at 9:26 AM
Sounds like we need to do more work on the scenarios - essentially we should gather:

 * Scenarios where the consumer *relies* on the uniqueness of the returned instances
 * Scenarios where the consumer is only giving the supplier an *opportunity* to return a new instance

I have a suspicion that we'll find may cases of each, and in fact we may have two separate needs here.

The first set of scenarios (off the top of my head) seem to be where identity and state are important (I'll bet we're talking views, view models etc.)

The second set of scenarios (again only on first impression) are more coarse grained and concerned with managing lifetime/units of work.

I've created a wiki page to gather these, please feel free to fill it in! http://cca.codeplex.com/wikipage?title=FuncFactoryScenarios

This may take some time, so meanwhile I'd like to include both types in the proposal: the main text will deal with Func<T> (it isn't going away regardless) and Factory<T> will be included as well, as a way of specifying the uniqueness restriction.

This way we can move forward while these questions are answered.

How does that sound for a plan?

Nick

On 26 February 2010 06:50, robertream <notifications@codeplex.com> wrote:

From: robertream

Well even if we Factory<T> advocates concede your points, I still think that the semantics of the behavior you are expecting ought to be considered when choosing a name. Given this, I still think Func is deficient, e.g. unnecessarily vague. What would you think about Locate or maybe Resolve? My rational is that Factory, Locate and Resolve might be considered functions but not all functions do construction, location or resolution. Some functions just do calculations. The vagueness of Func is fine for use cases such as with LINQ, but my impression was that, in order to avoid having IServiceLocator sprinkled everywhere, one of the key goals for this endeavor was to provide a standard set of types that would provide more expressive dependency semantics for containers to resolve dependencies with. Perhaps we ought to distill these different use cases where we might prefer a Func over a Factory and then provide delegates to better express the semantics for each use case?

I can think of places in my code that I want a new instance from the container each time and I'd like to tell it this, hence I would like a Factory. These instances I'm getting from the container are supposed to be mutable and transient and so I am certain I don't want to simply "resolve" or "locate", and I'm more than certain I don't want to "Func". And like I said before, if the container for some reason can't or doesn't want to create new instances each time it can create proxies or adapters that delegate to the cached instance and still not violate LSP. So I don't see a problem with more explicit dependency semantics for lifetime, construction location, etc. because sometimes the consumer cares about these things, and when it does then let the container bend the rules a little if it has to in order to conform to these semantics, but if you think Factory is a smell, then just don't use it.


On Thu, Feb 25, 2010 at 8:17 AM, kkozmic <notifications@codeplex.com> wrote:

From: kkozmic

ritchiep wrote:

Func<T> has the appearance of lack of focus.

And that's the beauty of it. Let us not loose focus of this whole endeavor - provide viable alternative to service locator - one that is flexible enough to be used in many scenarios.

With Func<T> due to it's lack of strong semantics we can use it in many contexts. With Factory<T>, we'd soon need MetaInstance<T> or InstanceProvider... then when we introduce 2nd generic parameter we're up for exponentially growing number of abstractions we'd need to cover every scenario this way. What's the point?

I rarely see an actual need of user code to depend on fact whether it receives new instance each time it requests an instance, whether there's a pool, or a singleton. I'm happy leaving that up to the container configuration part. In fact every time I do see such need, I find it more suitable to use Owned in the first place.

And let's not try to shield users from themselves. I think piece of guidance is more than enough for that.

Read the full discussion online.

To add a post to this discussion, reply to this email (cca@discussions.codeplex.com)

To start a new discussion for this project, email cca@discussions.codeplex.com

You are receiving this email because you subscribed to this discussion on CodePlex. You can unsubscribe or change your settings on codePlex.com.

Please note: Images and attachments will be removed from emails. Any posts to this discussion will also be available online at codeplex.com


Read the full discussion online.

To add a post to this discussion, reply to this email (cca@discussions.codeplex.com)

To start a new discussion for this project, email cca@discussions.codeplex.com

You are receiving this email because you subscribed to this discussion on CodePlex. You can unsubscribe or change your settings on codePlex.com.

Please note: Images and attachments will be removed from emails. Any posts to this discussion will also be available online at codeplex.com


Coordinator
Mar 10, 2010 at 7:58 PM

I've updated the proposal to include both Func and Factory - you can check it out here: http://cca.codeplex.com/Project/Download/FileDownload.aspx?DownloadId=110302

Cheers,

Nick