Dart - implementing a class method with argument as implemented class - dart

I am developing external library. Assume I have different implementations of logger class, I create abstract class ILogger which those classes can then implement.
I also have various implementations of log objects that I want to adhere to ILog abstract class so I expose it as well.
The problem is when my ILogger uses ILog as argument to one of its methods. I would assume that any of my implemented logger classes (that implement ILogger) would accept any arguments that are log classes (which implement ILog).
See my constrained example below:
abstract class ILog {
const LogImpl({required this.id});
final String id;
}
class Log implements ILog {
const Log({required this.id});
final String id;
}
abstract class ILogger {
void writeLog({
required LogImpl log,
required bool persist,
});
}
class Logger implements ILogger {
void writeLog({
required Log log,
required bool persist,
}) {
print('writing $log with persistence? $persist');
}
}
void main() {
final logger = Logger();
final log = Log(id: 'abcd-1234');
logger.writeLog(log: log, persist: true)
}
For this I get error:
Error: The parameter 'log' of the method 'Logger.writeLog' has type 'Log', which does not match the corresponding type, 'ILog', in the overridden method, 'ILogger.writeLog'.
Is there a way to solve this without resorting to applying generics?
The reason why my log object ILog needs to be abstract class instead of regular class that is extended is technical. One of my serialization libraries uses source code annotation which means that this annotation cannot be part of the library (because the annotation might be different for different applications).

The program doesn't compile because it's not sound.
Dart, and object oriented programming in general, is based around subtype substitutability. If your code works with an instance of a type, it works with an instance of a subtype too - the subtype can substitute for the supertype.
The Logger's writeLog method is not a valid override of the ILogger's writeLog method. The latter accepts an ILog as argument, and for the subtype to be able to substitute for that, it needs to accept an ILog too. However, it only accepts a Log, which is a subtype, and not any implementation of ILog.
One alternative is to admit that what you are writing is unsound, and tell the compiler to accept it anyway:
class Logger implements ILogger {
void writeLog({
required covariant Log log,
required bool persist,
}) {
print('writing $log with persistence? $persist');
}
}
Here the covariant tells the compiler that you know that Log does not satisfy the superclass parameter type of ILog, but it's OK. You know what you're doing, and no-one will ever call this function with something which isn't a proper Log. (And if they do anyway, it'll throw an error).
The other alternative, which is what I'd probably recommend, is to parameterize your classes on the Log it uses:
abstract class ILogger<L extends ILog> {
void writeLog({
required L log,
required bool persist,
});
}
class Logger implements ILogger<Log> {
void writeLog({
required Log log,
required bool persist,
}) {
print('writing $log with persistence? $persist');
}
}
With that, the Logger doesn't have to substitute for all ILoggers, only for ILogger<Log>, and it can do that soundly.
(Well, as soundly as the inherently unsound covariant generics allow, but the program will compile, and throw if you ever pass something which isn't a Log instance.)
In both cases the compiler will know that the argument to a Logger must be a Log. In both cases, you can fool the program by casting the Logger to the supertype ILogger/ILogger<ILog>, and then pass in an ILog to writeLog, but it takes at least a little effort to circumvent the type system.

Related

Check if a type implements an interface [duplicate]

I've recently found myself in a situation where I wanted to check if a Type is a subtype of another Type this is what I've tried
abstract class Record{}
class TimeRecord extends Record{}
void test(){
print(TimeRecord is Record); // return false but why ??
}
The only time it makes sense to check if one type is a subtype of another type is when at least one of the types is a type variable. (Otherwise, you can just look at the source and write a constant true or false into the code).
There is a way to check whether one type is a subtype of another, and it does use the is operator, but you need to have an instance as the first operand and a type as the second. You can't just create an instance of an unknown type, so we instead rely in Dart's covariant generics:
bool isSubtype<S, T>() => <S>[] is List<T>;
(You can use any generic class, or even create your own, instead of using List. All it needs is a way to create the object.)
Then you can write:
print(isSubtype<TimeRecord, Record>()); // true!
The is keyword is used to check if an object instance is an object of type T, and not if a type is another type:
abstract class Record{}
class TimeRecord extends Record{}
void test(){
print(TimeRecord() is Record); // returns true!
}
Just to add up to #lrn answer.
You could also do something like:
extension NullableObjectsExtensions<T> on T {
bool isSubtypeOf<S>() => <T>[] is List<S>;
bool isSupertypeOf<S>() => <S>[] is List<T>;
}
So this way you can test any variable anywhere.

Shared Interface Implementation in Remote Proxy Pattern

I'm brushing up on my design patterns knowledge by going through them in Dart, and I'm currently working on the remote proxy pattern. As I understand, the pattern implies a shared interface between the real object residing on a server machine, and the proxy object on a client machine.
I've managed to get all the networking between the client and server working fine, and i've set up a simple RPC API with dart's HttpServer and HttpClient, but there's one thing that's bugging me. The methods on the proxy object must be asynchronous because of the networking involved, but the real object's methods aren't asynchronous. It would appear that this makes it impossible for them to share an interface, and thus functional consistency between the two classes isn't guaranteed by the type system.
Is there a way to implement some kind of a future version of a certain interface in dart? I don't mean something that returns Future<SomeInterface>, but something where the methods of SomeInterface are implemented asynchronously with Future return types. What i'm looking for is something like:
abstract class IShared {
int foo();
}
class Bar implements IShared {
#override
int foo() {
// perform work here
return 0;
}
}
class BarProxy implements async IShared {
// Currently an invalid override
#override
Future<int> foo() async {
// perform async work here
return 0;
}
}
I'm aware that Future<IShared> implies something completely different entirely, but is there anything that could help implement what I want? Maybe i'm being too strict with requiring a shared interface between the real object and the proxy, but that's how it's always implemented in class diagrams.
Or perhaps there's a good pattern that i'm missing that can achieve this.
To be clear, I don't want to make the methods of the shared interface and non proxy object async with Future returns if possible.
Seems like a case for FutureOr which you can use to represent the case where you want to be able to return a object or same object packed inside an Future:
import 'dart:async';
abstract class IShared {
FutureOr<int> foo();
}
class Bar implements IShared {
#override
int foo() {
// perform work here
return 0;
}
}
class BarProxy implements IShared {
#override
Future<int> foo() async {
// perform async work here
return 0;
}
}

Guice Binding from Consumer Package

I am newbie for Guice and seeking help for the following use case :
I have developed one package say (PCKG) where the entry class of that package depends on other class like:
A : Entry point class --> #Inject A(B b) {}
B in turn is dependent on C and D like --> #Inject B(C c, D d) {}
In my binding module I am doing :
bind(BInterface).to(Bimpl);
bind(CInterface).to(CImpl);
...
Note I am not providing binding information for A as i want to provide its binding by its consumer class. (this is how the design is so my request is to keep the discussion on main problem rather than design).
Now my consumer class is doing like:
AModule extends PrivateModule {
protected void configure() {
bind(AInterface.class).annotatedWith(AImpl.class);
}
}
Also in my consumer package:
.(new PCKGModule(), new AModule())
Q1. Am i doing the bindings correctly in consumer class. I am confused because when i am doing some internal testing as below in my consumer package:
class testModule {
bind(BInterface).to(Bimpl);
bind(CInterface).to(CImpl)...
}
class TestApp {
public static void main(..) {
Guice.createInstance(new testModule());
Injector inj = Guice.createInstance(new AModule());
A obj = inj.getInstance(A.class);
}
}
It is throwing Guice creation exception.Please help me get rid of this situation.
Also one of my friend who is also naive to Guice was suggesting that I need to create B's instance in AModule using Provides annotation. But i really didn't get his point.
Your main method should look like this:
class TestApp {
public static void main(..) {
Injector injector = Guice.createInjector(new TestModule(), new AModule());
A obj = injector.getInstance(A.class);
}
Note that the Java convention is for class names to have the first letter capitalised.
I'm pretty sure your implementation of AModule isn't doing what you think it's doing either, but it's hard to be certain based on the information you've provided. Most likely, you mean to do this:
bind(AInterface.class).to(AImpl.class)`
There's no need to do anything "special" with A's binding. Guice resolves all the recursion for you. That's part of its "magic".
annotatedWith() is used together with to() or toInstance(), like this:
bind(AInterface.class).to(AImpl.class).annotatedWIth(Foo.class);
bind(AInterface.class).to(ZImpl.class).annotatedWIth(Bar.class);
Then you can inject different implementations by annotating your injection points, e.g.:
#Inject
MyInjectionPoint(#Foo AInterface getsAImpl, #Bar AInterface getsZImpl) {
....
}
It's worth also pointing out that you can potentially save yourself some boilerplate by not bothering with the binding modules (depending how your code is arranged) and using JIT bindings:
#ImplementedBy(AImpl.class)
public interface AInterface {
....
}
These effectively act as "defaults" which are overridden by explicit bindings, if they exist.

What is the purpose of the getter methods in Components in Dagger 2?

I am trying to understand Components in Dagger 2. Here is an example:
#Component(modules = { MyModule.class })
public interface MyComponent {
void inject(InjectionSite injectionSite);
Foo foo();
Bar bar();
}
I understand what the void inject() methods do. But I don't understand what the other Foo foo() getter methods do. What is the purpose of these other methods?
Usage in dependent components
In the context of a hierarchy of dependent components, such as in this example, provision methods such as Foo foo() are for exposing bindings to a dependent component. "Expose" means "make available" or even "publish". Note that the name of the method itself is actually irrelevant. Some programmers choose to name these methods Foo exposeFoo() to make the method name reflect its purpose.
Explanation:
When you write a component in Dagger 2, you group together modules containing #Provides methods. These #Provides methods can be thought of as "bindings" in that they associate an abstraction (e.g., a type) with a concrete way of resolving that type. With that in mind, the Foo foo() methods make the Component able to expose its binding for Foo to dependent components.
Example:
Let's say Foo is an application Singleton and we want to use it as a dependency for instances of DependsOnFoo but inside a component with narrower scope. If we write a naive #Provides method inside one of the modules of MyDependentComponent then we will get a new instance. Instead, we can write this:
#PerFragment
#Component(dependencies = {MyComponent.class }
modules = { MyDependentModule.class })
public class MyDependentComponent {
void inject(MyFragment frag);
}
And the module:
#Module
public class MyDepedentModule {
#Provides
#PerFragment
DependsOnFoo dependsOnFoo(Foo foo) {
return new DependsOnFoo(foo);
}
}
Assume also that the injection site for DependentComponent contains DependsOnFoo:
public class MyFragment extends Fragment {
#Inject DependsOnFoo dependsOnFoo
}
Note that MyDependentComponent only knows about the module MyDependentModule. Through that module, it knows it can provide DependsOnFoo using an instance of Foo, but it doesn't know how to provide Foo by itself. This happens despite MyDependentComponent being a dependent component of MyComponent. The Foo foo() method in MyComponent allows the dependent component MyDependentComponent to use MyComponent's binding for Foo to inject DependsOnFoo. Without this Foo foo() method, the compilation will fail.
Usage to resolve a binding
Let's say we would like to obtain instances of Foo without having to call inject(this). The Foo foo() method inside the component will allow this much the same way you can call getInstance() with Guice's Injector or Castle Windsor's Resolve. The illustration is as below:
public void fooConsumer() {
DaggerMyComponent component = DaggerMyComponent.builder.build();
Foo foo = component.foo();
}
Dagger is a way of wiring up graphs of objects and their dependencies. As an alternative to calling constructors directly, you obtain instances by requesting them from Dagger, or by supplying an object that you'd like to have injected with Dagger-created instances.
Let's make a coffee shop, that depends on a Provider<Coffee> and a CashRegister. Assume that you have those wired up within a module (maybe to LightRoastCoffee and DefaultCashRegister implementations).
public class CoffeeShop {
private final Provider<Coffee> coffeeProvider;
private final CashRegister register;
#Inject
public CoffeeShop(Provider<Coffee> coffeeProvider, CashRegister register) {
this.coffeeProvider = coffeeProvider;
this.register = register;
}
public void serve(Person person) {
cashRegister.takeMoneyFrom(person);
person.accept(coffeeProvider.get());
}
}
Now you need to get an instance of that CoffeeShop, but it only has a two-parameter constructor with its dependencies. So how do you do that? Simple: You tell Dagger to make a factory method available on the Component instance it generates.
#Component(modules = {/* ... */})
public interface CoffeeShopComponent {
CoffeeShop getCoffeeShop();
void inject(CoffeeService serviceToInject); // to be discussed below
}
When you call getCoffeeShop, Dagger creates the Provider<Coffee> to supply LightRoastCoffee, creates the DefaultCashRegister, supplies them to the Coffeeshop constructor, and returns you the result. Congratulations, you are the proud owner of a fully-wired-up coffeeshop.
Now, all of this is an alternative to void injection methods, which take an already-created instance and inject into it:
public class CoffeeService extends SomeFrameworkService {
#Inject CoffeeShop coffeeShop;
#Override public void initialize() {
// Before injection, your coffeeShop field is null.
DaggerCoffeeShopComponent.create().inject(this);
// Dagger inspects CoffeeService at compile time, so at runtime it can reach
// in and set the fields.
}
#Override public void alternativeInitialize() {
// The above is equivalent to this, though:
coffeeShop = DaggerCoffeeShopComponent.create().getCoffeeShop();
}
}
So, there you have it: Two different styles, both of which give you access to fully-injected graphs of objects without listing or caring about exactly which dependencies they need. You can prefer one or the other, or prefer factory methods for the top-level and members injection for Android or Service use-cases, or any other sort of mix and match.
(Note: Beyond their use as entry points into your object graph, no-arg getters known as provision methods are also useful for exposing bindings for component dependencies, as David Rawson describes in the other answer.)

e4 dependency reinjection order: field vs. method

I was quite surprised to see that there is no deterministic behavior for the order in which objects get reinjected.
public class Test {
#Inject private Boolean testBool;
#Inject
public void checkNewObject(Boolean testBoolNew) {
if (!testBoolNew.equals(this.testBool)) {
System.out.println("Out of sync!");
} else {
System.out.println("In sync!");
}
}
}
And this is how I use the class:
context.set(Boolean.class, new Boolean(true));
Test test = ContextInjectionFactory.make(Test.class, context);
context.set(Boolean.class, new Boolean(false));
So, sometimes I get the output:
In sync!
In sync!
And sometimes I get:
In sync!
Out of sync!
Is this really non deterministic or am I just overseeing something?
The documentation clearly states that the injection order should be:
Constructor injection: the public or protected constructor annotated with #Inject with the greatest number of resolvable arguments is selected
Field injection: values are injected into fields annotated with #Inject and that have a satisfying type
Method injection: values are injected into methods annotated with #Inject and that have satisfying arguments
See: https://wiki.eclipse.org/Eclipse4/RCP/Dependency_Injection#Injection_Order
I'm not sure, why this doesn't work as expected in your case.
How is equals() implemented in MyContent?
Is MyContent annotated with #Creatable and or #Singleton?
As a side note: Is this a practical or just an academic problem? Why is it necessary to inject the same instance into a field and into a method on the same target-instance? If you want to have a field variable to cache the value, you can set this from the method.
If you feel this is a bug, please file it here: https://bugs.eclipse.org/bugs/enter_bug.cgi?product=Platform

Resources