I have the following inheritance structure in Dart code, and am wondering whether there is a method signature that accounts for both class A and class B for T, so that I have a static check and don't have to typecast. Is this possible?
abstract class A {
String one;
}
abstract class B {
String two;
}
class C implements A, B {
String one;
String two;
}
class D implements A, B {
String one;
String two;
}
void _ohNo<T extends A, B>(T t) {
print(t.one); // valid
print(t.two); // invalid: getter not defined
}
void _ohNo2<T extends A, T extends B>(T t) {} // invalid: T already defined
Could be a workaround:
abstract class Both extends A with B {}
class C implements Both {
String one = '';
String two = '';
}
class D implements Both {
String one = '';
String two = '';
}
void ohNo<T extends Both>(T t) {
print(t.one);
print(t.two);
}
Related
Consider this code
final dynamic bar;
class Foo<T> {
const Foo(this.bla) : assert(T == A, T == B);
final T bla;
}
...
final Foo foo = Foo(bla); // Assert will trigerred because bla is dynamic even it is A type.
I don't know the bla type but i can assured its on a A type or B type.
I want to do something like this?
final Foo foo = Foo<bla.runtimeType>(bla);
You should write base class that encompasses class A and B. You should send class Foo that derives from this base class.
abstract class Base{
void printName();
}
class A extends Base{
A();
#override
printName(){
print("A class");
}
}
class B extends Base{
B();
#override
printName(){
print("b class");
}
}
class Foo {
Base bla;
Foo(this.bla);
}
void main(){
dynamic a=A();
Foo fooA = Foo(a);
fooA.bla.printName();
dynamic b=B();
Foo fooB = Foo(b as Base);
fooB.bla.printName();
}
You should be careful here Foo fooB = Foo(b as Base);. If this cast cannot be done, it will give an error.I suggest you use try catch block
look here for generic type check
because T==A (any className) in assert blog will not give correct result
for more information
void foo<T extends num, String> (T t) {
if (t is String) {
String s = t; // Error
}
}
A value of type 'T' can't be assigned to a variable of type 'String'.
You won't be able to do this with base Dart as your generic type T can only extends one class.
The only way I would see such a behavior feasible would be by using a 3rd party packages such as dartz with its Either type.
Example
void foo<T extends num>(Either<T, String> t) {
final String s;
if (t.isRight()) {
s = (t as Right<T, String>).value;
} else {
s = (t as Left<T, String>).value.toStringAsFixed(3);
}
print(s);
}
foo(Left(1.0)); // prints '1.000'
foo<int>(Right('bar')); // prints 'bar'
There is no syntax to specify that a generic type implement multiple interfaces, so there is no way for this to work with compile-time checks.
Furthermore, your particular example can't work because num and String cannot be extended nor implemented, so it's impossible to have a type that implements both.
If we change your example, which relies on a runtime check, to use two custom types, it still won't work:
class C1 {}
class C2 {
void f() => print('C2.f');
}
class C3 implements C1, C2 {
#override
void f() => print('C3.f');
}
void foo<T extends C1>(T t) {
if (t is C2) {
t.f(); // 'f' isn't defined for the type <unknown>
}
}
See https://github.com/dart-lang/language/issues/2047: t isn't related to C2, so the is C2 check unfortunately will not automatically promote it to C2. You instead can use a runtime cast:
void foo<T extends C1>(T t) {
if (t is C2) {
(t as C2).f();
}
}
or upcast to Object/dynamic first:
void foo<T extends C1>(T t) {
Object t0 = t;
if (t0 is C2) {
t0.f();
}
}
But really you should just use T extends C3 if possible.
interfaces
abstract class Adder<T> {
T add(T a, T b);
}
abstract class Multiplier<T> {
T multiply(T a, T b);
}
abstract class Displayer<T> {
void display(T a);
}
An implementation that just happens to implement all three.
class IntImpl implements Adder<int>, Multiplier<int>, Displayer<int> {
#override
int add(int a, int b) {
return a + b;
}
#override
int multiply(int a, int b) {
return a * b;
}
#override
void display(int a) {
print('printing: ${a}');
}
}
A consumer that needs support for two of the interfaces.
But, I could not find how to declare such a thing.
class DisplayingAdder<T, K extends Adder<T>> {
final K engine;
DisplayingAdder(this.engine);
T addAndDisplay(T a, T b) {
final r = engine.add(a, b);
// How do I change DisplayingAdder class parametrization to make the next line functional?
// engine.display(r);
return r;
}
}
Code to exercise the above
void main() {
final e1 = IntImpl();
final da = DisplayingAdder(e1);
da.addAndDisplay(3,4);
}
Not sure what can be changed to allow the generic parameter to declare support for more than one abstract class.
You can't restrict a generic type to a type that implements multiple supertypes. The best you're going to have to do is separate engine into an object that implements Adder and an object that implements Displayer, then pass the instance of IntImpl to both. (This is more scalable anyway since it also allows you to pass different values to each if you wanted.)
class DisplayingAdder<T, A extends Adder<T>, D extends Displayer<T>> {
final A adder;
final D displayer;
DisplayingAdder(this.adder, this.displayer);
T addAndDisplay(T a, T b) {
final r = adder.add(a, b);
displayer.display(r);
return r;
}
}
void main() {
final e1 = IntImpl();
final da = DisplayingAdder(e1, e1);
da.addAndDisplay(3,4);
}
Hi I just would like to know if there is any difference between giving abstract keyword or not like so.
// with
abstract class A {}
class B extends A {}
// without
class A {}
class B extends A {}
Should I give it?
With abstract you can omit implementations of methods and getters/setters
// with
abstract class A {
int foo();
String get bar;
set baz(String value);
}
var a = A(); // error about instantiating abstract class
class B extends A {
// error about missing implementations
}
var b = B(); // ok
// without
class A {
int foo(); // error about missing implementation
String get bar; // error about missing implementation
set baz(String value); // error about missing implementation
}
class B extends A {}
So basically, I have a situation where I want to inject primitive types into a class (i.e. a String and an Integer). You can think of a URL and port number for an application as example inputs. I have three components:
Now say I have a class, which does take in these params:
public class PrimitiveParamsDIExample {
private String a;
private Integer b;
public PrimitiveParamsDIExample(String a, Integer b) {
this.a = a;
this.b = b;
}
}
So my question here is simple. How do I inject a and b into class PrimitiveParamsDIExample?
In general, this is also asking how to inject parameters that are decided on runtime as well. If I have a and b above, read from STDIN or from an input file, they're obviously going to be different from run to run.
All the more, how do I do the above within the HK2 framework?
EDIT[02/23/15]: #jwells131313, I tried your idea, but I'm getting the following error (this one for the String param; similar one for int):
org.glassfish.hk2.api.UnsatisfiedDependencyException: There was no object available for injection at Injectee(requiredType=String,parent=PrimitiveParamsDIExample,qualifiers
I set up classes exactly as you did in your answer. I also overrode the toString() method to print both variables a and b in PrimitiveParamsDIExample. Then, I added the following in my Hk2Module class:
public class Hk2Module extends AbstractBinder {
private Properties properties;
public Hk2Module(Properties properties){
this.properties = properties;
}
#Override
protected void configure() {
bindFactory(StringAFactory.class).to(String.class).in(RequestScoped.class);
bindFactory(IntegerBFactory.class).to(Integer.class).in(RequestScoped.class);
bind(PrimitiveParamsDIExample.class).to(PrimitiveParamsDIExample.class).in(Singleton.class);
}
}
So now, I created a test class as follows:
#RunWith(JUnit4.class)
public class TestPrimitiveParamsDIExample extends Hk2Setup {
private PrimitiveParamsDIExample example;
#Before
public void setup() throws IOException {
super.setupHk2();
//example = new PrimitiveParamsDIExample();
example = serviceLocator.getService(PrimitiveParamsDIExample.class);
}
#Test
public void testPrimitiveParamsDI() {
System.out.println(example.toString());
}
}
where, Hk2Setup is as follows:
public class Hk2Setup extends TestCase{
// the name of the resource containing the default configuration properties
private static final String DEFAULT_PROPERTIES = "defaults.properties";
protected Properties config = null;
protected ServiceLocator serviceLocator;
public void setupHk2() throws IOException{
config = new Properties();
Reader defaults = Resources.asCharSource(Resources.getResource(DEFAULT_PROPERTIES), Charsets.UTF_8).openBufferedStream();
load(config, defaults);
ApplicationHandler handler = new ApplicationHandler(new MyMainApplication(config));
final ServiceLocator locator = handler.getServiceLocator();
serviceLocator = locator;
}
private static void load(Properties p, Reader r) throws IOException {
try {
p.load(r);
} finally {
Closeables.close(r, false);
}
}
}
So somewhere, the wiring is messed up for me to get an UnsatisfiedDependencyException. What have I not correctly wired up?
Thanks!
There are two ways to do this, but one isn't documented yet (though it is available... I guess I need to work on documentation again...)
I'll go through the first way here.
Basically, you can use the HK2 Factory.
Generally when you start producing Strings and ints and long and scalars like this you qualify them, so lets start with two qualifiers:
#Retention(RUNTIME)
#Target( { TYPE, METHOD, FIELD, PARAMETER })
#javax.inject.Qualifier
public #interface A {}
and
#Retention(RUNTIME)
#Target( { TYPE, METHOD, FIELD, PARAMETER })
#javax.inject.Qualifier
public #interface B {}
then write your factories:
#Singleton // or whatever scope you want
public class StringAFactory implements Factory<String> {
#PerLookup // or whatever scope, maybe this checks the timestamp?
#A // Your qualifier
public String provide() {
// Write your code to get your value...
return whatever;
}
public void dispose(String instance) {
// Probably do nothing...
}
}
and for the Integer:
#Singleton // or whatever scope you want
public class IntegerBFactory implements Factory<Integer> {
#PerLookup // or whatever scope, maybe this checks the timestamp?
#B // Your qualifier
public Integer provide() {
// Write your code to get your value...
return whatever;
}
public void dispose(String instance) {
// Probably do nothing...
}
}
Now lets re-do your original class to accept these values:
public class PrimitiveParamsDIExample {
private String a;
private int b;
#Inject
public PrimitiveParamsDIExample(#A String a, #B int b) {
this.a = a;
this.b = b;
}
}
Note I changed Integer to int, well... just because I can. You can also just use field injection or method injection in the same way. Here is field injection, method injection is an exercise for the reader:
public class PrimitiveParamsDIExample {
#Inject #A
private String a;
#Inject #B
private int b;
public PrimitiveParamsDIExample() {
}
}
There are several ways to bind factories.
In a binder: bindFactory
Using automatic class analysis: addClasses
An EDSL outside a binder: buildFactory