Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

0.4.0 #19

Closed
pleerock opened this issue Jul 6, 2016 · 19 comments
Closed

0.4.0 #19

pleerock opened this issue Jul 6, 2016 · 19 comments

Comments

@pleerock
Copy link
Contributor

pleerock commented Jul 6, 2016

Im going to release next 0.4.0 version. There are a lot of changes and improvements, and breaking changes too. Last breaking change I made today - I've changed ValidationError signature. Before releasing I wanted to ask you guys @zakhenry @DominicBoettger if there is something you think is wrong in this release, or something should be added/changed before this release.

Thank you

@zakhenry
Copy link
Contributor

zakhenry commented Jul 6, 2016

Looks good to me, the upgrade for me to 0.4.0 was relatively straight forward, only complexity was in dealing with the new container

@pleerock
Copy link
Contributor Author

pleerock commented Jul 6, 2016

really? it was only one-line change

@zakhenry
Copy link
Contributor

zakhenry commented Jul 6, 2016

From memory the difference was that now everything is retrieved from the container (previously just instantiated), and I was providing my own container, but it had no reference to Validator for example. So I had to extend my container to fall back to instantiation.

@zakhenry
Copy link
Contributor

zakhenry commented Jul 6, 2016

The only way to make that simpler would be do do the following:

Change

export function useContainer(iocContainer: { get(someClass: any): any }) {
    container = iocContainer;
}

To

export function useContainer(iocContainer: { get(someClass: any): any }) {
    const originalContainer = container;
    container = {
        get: (someClass: any) => {
            try {
                return iocContainer.get(someClass);
            } catch () {
                return originalContainer.get(someClass);
            }
        }
    }
}

(The above is a crude proof of concept to demonstrate the point, it should be a cleaner implementation where the original container is a class that can have a container passed to it to try first)

@zakhenry
Copy link
Contributor

zakhenry commented Jul 6, 2016

Actually you could probably use my implementation directly:

interface InjectableClass<T> {
    new (...args: any[]): T
}

interface IOCContainer {
    get(someClass: any): any
}

class Container implements IOCContainer {

    protected externalInjector: IOCContainer;

    protected instances: WeakMap<InjectableClass<any>, any> = new WeakMap();

    /**
     * Get the instance of a class when there is no dependency
     * @param staticClass
     * @returns {any}
     */
    public noDependencyGet<T>(staticClass: InjectableClass<T>): T {

        if (!this.instances.has(staticClass)) {
            this.instances.set(staticClass, new staticClass());
        }

        return this.instances.get(staticClass);
    }

    public get<T>(staticClass: InjectableClass<T>): T {
        if (!this.externalInjector) {
            return this.noDependencyGet(staticClass);
        }

        try {
            return this.externalInjector.get(staticClass);
        } catch (e) {
            return this.noDependencyGet(staticClass);
        }
    }

    public setContainer(iocContainer: IOCContainer): this {
        this.externalInjector = iocContainer;
        return this;
    }
}

@pleerock
Copy link
Contributor Author

pleerock commented Jul 6, 2016

as I understood, your container cannot simply return instance of the class it received, thats why fallback to original container is required. But I thought most containers working like this: you send them refrenece to the class / token and they return you instance of this class, without complaining

@zakhenry
Copy link
Contributor

zakhenry commented Jul 6, 2016

Yep thats the problem, I guess not all containers do that - I'm just using the Angular 2 injector, so probably a fairly common use case. The Angular 2 injector stores a reference of all provided Tokens, and if there is no provider for that token it throws a NoProvider exception

@pleerock
Copy link
Contributor Author

pleerock commented Jul 6, 2016

I guess it will not give you instance of the class, until you explicitly "provide" it?

@zakhenry
Copy link
Contributor

zakhenry commented Jul 6, 2016

Correct, and providing tokens is done when the injector instance is created.

For example:

import { ReflectiveInjector } from  '@angular/core';
const providers = ReflectiveInjector.resolve([
    {provide: Validator, useClass: MyValidator}
]);
const injector  = ReflectiveInjector.fromResolvedProviders(providers);

@pleerock
Copy link
Contributor Author

pleerock commented Jul 6, 2016

got it.

the reason why angular's container works differently then others, I think mostly because it was designed to work with tree-like components. And this design works fine with tree-like components when you can provide any instance on any level of the tree - I like this concept when designing view components

@zakhenry
Copy link
Contributor

zakhenry commented Jul 6, 2016

Yea, also the Angular container can handle hierarchical dependencies - the injected class can be dependent on other injected classes.

I actually have a unit test showing this working with a custom validator having external dependencies, see https://github.com/ubiquits/ubiquits/blob/master/src/common/stores/store.spec.ts#L16-71

@pleerock
Copy link
Contributor Author

pleerock commented Jul 6, 2016

so, about fallback, probably I need not only catch an exceptions, but also check for null/undefined references?

get: (someClass: any) => {
            try {
               const instance = iocContainer.get(someClass);
               if (instance)
                   return instance;
            } catch (error) {
            }
            return originalContainer.get(someClass);
        }

and what shall I do with error? is it a really good to catch errors and completely ignore them? can be a situation when there is some another error, that you user should be aware of?

@zakhenry
Copy link
Contributor

zakhenry commented Jul 6, 2016

Yea thats probably a good idea to check if defined. Good point on the error, maybe if a setContainerFallbackCondition((error:Error):boolean):this could be added?

try {
    const instance = iocContainer.get(someClass);
    if (instance) {
        return instance;
    }
} catch (error) {
    if (this.containerFallbackCondition && !this.containerFallbackCondition(error)) {
        throw error;
    }
}
return originalContainer.get(someClass);

@pleerock
Copy link
Contributor Author

pleerock commented Jul 6, 2016

this makes it complicated, I think this kind of logic should be resolved on client side. Maybe something simple like this:

useContainer(container, { fallback: true, fallbackOnErrors: true });
interface UseContainerOptions {

    /**
     * If set to true, then default container will be used in the case if given container haven't returned anything.
     */
    fallback?: boolean;

    /**
     * If set to true, then default container will be used in the case if given container thrown an exception.
     */
    fallbackOnErrors?: boolean;

}

@zakhenry
Copy link
Contributor

zakhenry commented Jul 6, 2016

Maybe if fallbackOnErrors could be fallbackOnErrors?: boolean | (error:Error):boolean ? Best of both worlds?

@pleerock
Copy link
Contributor Author

pleerock commented Jul 6, 2016

It will be same as

 const instance = iocContainer.get(someClass);
    if (instance) {
        return instance;
    }
  return originalContainer.get(someClass);

e.g. without try/catch. Without fallback: true it will work like now, .e.g without any fallback at all.

Maybe if fallbackOnErrors could be fallbackOnErrors?: boolean | (error:Error):boolean ? Best of both worlds?

I think it overcomplicates it - "handing error based on some function that returns true or false for this error" - seems very specific feature, and if needed user should handle it by themself, by passing a custom container that handle it.

@zakhenry
Copy link
Contributor

zakhenry commented Jul 6, 2016

Yea sorry I misread the comments in the interface, understood now

@pleerock
Copy link
Contributor Author

pleerock commented Jul 6, 2016

here is how it will look like: #20

@pleerock
Copy link
Contributor Author

pleerock commented Jul 6, 2016

@pleerock pleerock closed this as completed Jul 6, 2016
@gempain gempain mentioned this issue Jun 21, 2017
@typestack typestack locked and limited conversation to collaborators Jul 19, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Development

No branches or pull requests

2 participants