Future<T> Relationship

Mar 1, 2010 at 12:34 PM
Edited Mar 2, 2010 at 1:44 PM

Firstly, there have been some great discussions going around here, and I've picked up some nice pointers for creating DI adapters in my little IoC tool. Now, I wanted to put across one of the scenarios that I've encountered, it relates to some resource that might not be immediately resolvable/available but the use-case might be such that it would be at some indeterminate point in the future. Now, this is semantically different form Lazy<T> in that it defines a checkpoint to the lazy creation of the resource by biasing it on some contextual criteria. Now, the criteria could be based on some business logic or more-likely from the perspective of an IoC/DI tool it could be based on the resource being made available in the backing catalog. Also, this is somewhat related to Optional<T>, in the sense that it would not stop the processing of the dependency tree if the resource is not currently available, but at the same time we not saying this is entirely optional. 

Now, I've thought about two models for this, one of which extends Lazy<T>:

public class Future<T> : Lazy<T>
{
    public bool IsValueAvaliable { get;  }
}

or,

public class Future<T>
{
    public bool IsValueAvaliable { get;  }

    public T Value { get;  }
}

Optionally, we can have some sort of notification mechanism to indicate when the resource is made available - but that can be both tricky and expensive to setup. Personally, I'll prefer a pull sort of a model rather than a push one, but then again we could have both these types of semantics represented separately.

What do you guys think?

Coordinator
Mar 2, 2010 at 12:00 PM

Howdy, thanks for the suggestion!

On first impressions it sounds like this is really only supportable in MEF today, where recomposition is available.

I think the "push model" relationship makes sense in some scenarios, but I don't think the scenarios are portable at the current time (we're really aiming for portability in this project right now.) They'll be interesting to watch though.

Mar 4, 2010 at 7:16 AM
Edited Mar 4, 2010 at 10:34 AM

Well I don't think a Future<T> relationship is only applicable where recomposition is available, a pull model can be used by traditional IoC/DI tools. Let me give you an example, say we have a Silverlight Prism project that dynamically/lazily loads modules which themselves reside in independent xap files, and then in ModuleA I require the services of ILogger but its implementation resides in ModuleB. Now, because the dynamic/lazy loading schedule is indeterminate from the the perspective of my class, I can specfically ask for a Future<ILogger> dependency. And then within my class logic I can check on Future<ILogger>.IsValueAvaliable to know if the resource is now consumable, if so, I can resolve it via its Value property - this essentially is like a pull or polling model and it doesn't require recomposition. The real benefit is that it helps with abstracting away the IoC/DI tool specifics, rather than having to loop around the IoC/DI APIs. 

On the other hand if we had a FuturePush<ILogger> version that raised an event or notification when the service is available, that would be good for recomposition scenarios like with MEF - which honestly would be a superior solution as long as we don't run into cross-threading and/or memory-leak issues. In my solution I've already implemented the pull model, and it is really proving to be helpful from the consumer-code's perspective, since I don't need to worry about timing issues (as much). And going forward with more asynchronous consumption of data and services, I for-see the need for this.

Mar 4, 2010 at 8:34 AM

If you consider the scenario you describe, it's just a special case of requiring an arbitrary number of dependencies. What you are really saying is:

I need zero or one instances of my dependency

You may not currently think of it this way, but your consuming code must have two branches. One to handle the case where IsValueAvailable is false, and one to handle the case where it's true. Something like this:

if (this.dep.IsValueAvailable)
{
    this.dep.Value.DoStuff("foo");
}

You could achieve the same result with the same amount of code and a more general solution by taking a dependency on IEnumerable<T>. Instead of the code above, you would have:

foreach (var dep in this.deps)
{
    dep.DoStuff("foo");
}

Obviously my example is a bit contrived because the dependency's API is a Command, not a Query (in CQS terminology). For Query-based APIs you need to deal with the fact that there may be more than one result, but that's not a lot different from dealing with the case when there are none.

The beauty of using IEnumerable<T> is that it enables deferred execution, so if the dependency is not yet available, you simply get an empty enumerator, but the next time you enumerate, the enumerator may contain the dependency because it has become available in the meantime. Another nice thing about polymorphic sequences is that we can provide default implementations using the Null Object pattern by appending a NullDependency to the list to make sure that some sort of minimal behavior is alway ensured.

An old colleague of mine once said:

The most difficult scale-out operation is that from 1 to 2. After that, the rest is easy.

I'm not saying that using IEnumerable<T> can always replace something like Future<T>, but in most cases, you should seriously consider if it wouldn't be a better design.

Mar 4, 2010 at 10:20 AM
Edited Mar 4, 2010 at 12:20 PM

Agreed, technically you might be achieve the same net result by using an IEnumerable<T> but by using the same logic we could banish Lazy<T>, since like you said IEnumerables support deferred execution. It is not that clear cut. I think when we speak of "higher order dependencies" there is something to be said about the importance of semantics, and I suppose that was also well documented by the arguments both for/against Func<T> v/s Factory<T>. And just like Lazy<T> represents a delayed resolution, a Future<T> represents an indeterminately delayed resolution, and I think the richness of that semantic and equally the abstraction of the IoC/DI specifics is where the value of something like Future<T> is. 

Also, in terms of compactness of the API, here is a small snipped from my framework using Future<T>:

 

[ResolveResource("SpecialService")]
public Future<ISomeService> SomeService { get; set; }

Above I'm saying I want the "SpecialService" keyed resource of type ISomeService, and I'm not sure when it might be available - now, to do the same thing with IEnumerable<T> you might have to bring down the meta-data and it can easily both get messy and/or expensive thereon. Also, given an IEnumerable<T> with many registered resources, I would consider it wasteful to go through even one non-matching resource, and that is not counting any unknown side-effects that might happen when creating a non-used resource.

Mar 4, 2010 at 11:48 AM

The discussion boils down to a question of semantics, just as it did with the discussion about Func<T> vs. Factory<T>. I'm firmly on the side that favor Func<T>, and I would presume that you are in the other camp. I do understand the arguments put forth regarding semantics, but I just don't find them compelling. Eventually, it's a subjective evaluation, so I completely understand that opposing opinions thrive :)

For the record, I find Lazy<T> a Leaky Abstraction as well - when it comes to DI: I have no problem with the type itself, I just don't think it is proper to represent a dependency in this way.

My viewpoint is that DI is not a goal in itself. It's just a means to achieve loosely coupled code. This means that my personal philosophy is that code should be written to be DI-friendly while still being completely DI-agnostic. According to that philosophy, your example has several issues:

  • It explicitly uses a particular DI Container by applying an attribute.
  • It explictly uses weakly typed metadata (a string) to determine which implementation it requests. How can a named instance relate to the Domain you are trying to model? It very rarely does.
  • Properties are considered optional, so the combined contract seems redundant or vague. I don't have to assign SomeService at all, but even if I do, it may not be available? How does that differ from the scenario where I don't assign the dependency at all?

As an overall principle I salute explicitness as a good thing, but I find explicitness about dependency lifetime to be wrong because it creates ambiguity about who controls the lifetime of injected dependencies.

With relation to DI, the only thing that explicitness accomplishes is to announce to the world that a DI Container is expected to be in use. I consider this detrimental instead of beneficial.

One of the current trends related to software development is a move towards a more declarative model - we would rather express what than how. This is one of the key benefits of LINQ to objects, and one derived benefit is that it makes migration to parallelism possible with PLINQ - exactly because of the (more) declarative nature of LINQ.

I think that DI should be treated the same way. I can use Constructor Injection to statically declare that I require a certain dependency. The more explicit I become, the less declarative. Each time I explicitly state something, I remove a degree of freedom.

Getting back to Future<T>, my point is that you don't have to explicitly state that a dependency may become available in the future. The only thing this accomplishes is to add complexity in the wrong place. Let's look at an example where the dependency returns a value (and assuming that we don't want to use IEnumerable<T>):

string foo = "bar";
if (this.dep.IsAvailable)
{
    foo = this.dep.Value.GetFoo();
}

Notice how you need to explicitly define default values to avoid null references. It would be much better if you could just write:

string foo = this.dep.GetFoo();

But what if the dependency isn't available yet? We can deal with that issue if it ever becomes relevant, but it's a Leaky Abstraction to let the consumer deal with this issue. It's also a violation of the Single Responsibility Principle. A much more elegant way to deal with this situation is to wrap the dependency in a lazy-loading implementation that uses a Null Object as a stand-in until the 'real' dependency becomes available.

This might look something like this:

public class NullOrFutureDep : IDep
{
    public string GetFoo()
    {
        IDep realDep = this.PollRealDep();
        if(realDep != null)
        {
            return realDep.GetFoo();
        }
        return "bar";
    }

    private IDep PollRealDep()
    {
        // implement availability mechanism here
    }
}

We have now cleanly separated the responsibility of managing the dependency from consuming it, but the best part is that we have deferred the decision until the Last Responsibile Moment.

It would be cool to have a type that could automatically emit a Future implementation like the above. I suspect this would be something that could be implemented fairly simply with Castle DynamicProxy, but now I'm just guessing...

Mar 5, 2010 at 1:00 PM
Edited Mar 5, 2010 at 1:01 PM

On a more constructive note, I would love having a Future<T> class in CCA, but just not used as part of a contract declaration. I would like one that looks like this:

public class Future<T>
{
    public Future(T nullObject, Func<T> poll)

    public T Object { get; }
}

As described in the example in my previous post, the Object property would emit an implementation of T that for each member of T polls the poll Func. If it returns null, the emitted implementation defaults to use the supplied nullObject, but as soon as poll returns an instance, it switches state and starts using that instance exclusively instead of nullObject.

Notice how much this looks like a Mock object. I wonder how much work it would require to enable Moq to do something like that...

The point is that a consumer would not explicitly request Future<T>, but just T as normally:

public class MyClass
{
    public MyClass(IDep dep)
}

However, if we need to implement the Future lifetime, we can simply register it in any container that supports factory methods. In Windsor it would look like this:

container.Register(Component
    .For<IDep>()
    .UsingFactoryMethod(k => k.Resolve<Future<IDep>>().Object));

and in autofac something like this (I think):

var builder = new ContainerBuilder();
// ...
builder.Register<IDep>((c, p) => c.Resolve<Future<IDep>>().Object);

I would also very much like to see a Lazy<T> that does this, but I realize that this name is already taken in .NET 4, and since it does something else, we would need a new name.