I want to create a new object of given type inside of generic in Vala language.
class MyClass <T> : GLib.Object
{
protected T data;
public MyClass ()
{
data = new T ();
}
}
I understand that this can't work, but what is the way to do something like that?
You are probably best instantiating it when calling the constructor for MyClass:
void main () {
new MyClass<Test> (new Test ());
new MyClass<Example> (new Example ());
}
class MyClass <T>
{
protected T data;
public MyClass (T data)
{
this.data = data;
}
}
class Test {}
class Example {}
Vala generics do not currently provide constraints. If you are going to pass in a dependency in this way you may want to consider using an interface type instead of a generic type.
Update
If you are wanting to implement a factory then an interface with a static method or function is probably best:
void main () {
var a = CommandFactory.get_command ("A");
var b = CommandFactory.get_command ("B");
a.run ();
b.run ();
}
namespace CommandFactory {
Command get_command (string criteria) {
Command result = null;
switch (criteria) {
case "A":
result = new CommandA ();
break;
case "B":
result = new CommandB ();
break;
default:
assert_not_reached ();
}
return result;
}
}
interface Command:Object {
public abstract void run ();
}
class CommandA:Object, Command {
void run () { print ("A\n"); }
}
class CommandB:Object, Command {
void run () { print ("B\n"); }
}
I assume by 'abstract fabric pattern' you mean 'abstract factory pattern'? You could try using GType introspection to then instantiate the Object, but it must be a GObject and you by pass Vala's static analysis checks:
void main () {
new MyClass<Example> (new Example ());
/* These will fail at runtime
new MyClass<string> ("this will fail at runtime");
new MyClass<ThisWillFailAtRuntime> (new ThisWillFailAtRuntime ());
*/
}
class MyClass <T>
{
protected T data;
public MyClass (T data)
{
assert (typeof(T).is_object());
this.data = Object.new (typeof(T));
}
}
class Example:Object {}
class ThisWillFailAtRuntime {}
Note that Object.new() is also a static method.
I'm not sure what you are trying to achieve, but you are probably better looking more closely at interfaces and favouring composition over inheritance in your object data model.
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 {}
I was wondering if is possible to create an instance of a generic type in Dart. In other languages like Java you could work around this using reflection, but I'm not sure if this is possible in Dart.
I have this class:
class GenericController <T extends RequestHandler> {
void processRequest() {
T t = new T(); // ERROR
}
}
I tried mezonis approach with the Activator and it works. But it is an expensive approach as it uses mirrors, which requires you to use "mirrorsUsed" if you don't want to have a 2-4MB js file.
This morning I had the idea to use a generic typedef as generator and thus get rid of reflection:
You define a method type like this: (Add params if necessary)
typedef S ItemCreator<S>();
or even better:
typedef ItemCreator<S> = S Function();
Then in the class that needs to create the new instances:
class PagedListData<T>{
...
ItemCreator<T> creator;
PagedListData(ItemCreator<T> this.creator) {
}
void performMagic() {
T item = creator();
...
}
}
Then you can instantiate the PagedList like this:
PagedListData<UserListItem> users
= new PagedListData<UserListItem>(()=> new UserListItem());
You don't lose the advantage of using generic because at declaration time you need to provide the target class anyway, so defining the creator method doesn't hurt.
You can use similar code:
import "dart:mirrors";
void main() {
var controller = new GenericController<Foo>();
controller.processRequest();
}
class GenericController<T extends RequestHandler> {
void processRequest() {
//T t = new T();
T t = Activator.createInstance(T);
t.tellAboutHimself();
}
}
class Foo extends RequestHandler {
void tellAboutHimself() {
print("Hello, I am 'Foo'");
}
}
abstract class RequestHandler {
void tellAboutHimself();
}
class Activator {
static createInstance(Type type, [Symbol constructor, List
arguments, Map<Symbol, dynamic> namedArguments]) {
if (type == null) {
throw new ArgumentError("type: $type");
}
if (constructor == null) {
constructor = const Symbol("");
}
if (arguments == null) {
arguments = const [];
}
var typeMirror = reflectType(type);
if (typeMirror is ClassMirror) {
return typeMirror.newInstance(constructor, arguments,
namedArguments).reflectee;
} else {
throw new ArgumentError("Cannot create the instance of the type '$type'.");
}
}
}
I don't know if this is still useful to anyone. But I have found an easy workaround. In the function you want to initialize the type T, pass an extra argument of type T Function(). This function should return an instance of T. Now whenever you want to create object of T, call the function.
class foo<T> {
void foo(T Function() creator) {
final t = creator();
// use t
}
}
P.S. inspired by Patrick's answer
2022 answer
Just came across this problem and found out that although instantiating using T() is still not possible, you can get the constructor of an object easier with SomeClass.new in dart>=2.15.
So what you could do is:
class MyClass<T> {
final T Function() creator;
MyClass(this.creator);
T getGenericInstance() {
return creator();
}
}
and when using it:
final myClass = MyClass<SomeOtherClass>(SomeOtherClass.new)
Nothing different but looks cleaner imo.
Here's my work around for this sad limitation
class RequestHandler {
static final _constructors = {
RequestHandler: () => RequestHandler(),
RequestHandler2: () => RequestHandler2(),
};
static RequestHandler create(Type type) {
return _constructors[type]();
}
}
class RequestHandler2 extends RequestHandler {}
class GenericController<T extends RequestHandler> {
void processRequest() {
//T t = new T(); // ERROR
T t = RequestHandler.create(T);
}
}
test() {
final controller = GenericController<RequestHandler2>();
controller.processRequest();
}
Sorry but as far as I know, a type parameter cannot be used to name a constructor in an instance creation expression in Dart.
Working with FLutter
typedef S ItemCreator<S>();
mixin SharedExtension<T> {
T getSPData(ItemCreator<T> creator) async {
return creator();
}
}
Abc a = sharedObj.getSPData(()=> Abc());
P.S. inspired by Patrick
simple like that.
import 'dart:mirrors';
void main(List<String> args) {
final a = A<B>();
final b1 = a.getInstance();
final b2 = a.getInstance();
print('${b1.value}|${b1.text}|${b1.hashCode}');
print('${b2.value}|${b2.text}|${b2.hashCode}');
}
class A<T extends B> {
static int count = 0;
T getInstance() {
return reflectClass(T).newInstance(
Symbol(''),
['Text ${++count}'],
{Symbol('value'): count},
).reflectee;
}
}
class B {
final int value;
final String text;
B(this.text, {required this.value});
}
Inspired by Patrick's answer, this is the factory I ended up with.
class ServiceFactory<T> {
static final Map<Type, dynamic> _cache = <String, dynamic>{};
static T getInstance<T>(T Function() creator) {
String typeName = T.toString();
return _cache.putIfAbsent(typeName, () => creator());
}
}
Then I would use it like this.
final authClient = ServiceFactory.getInstance<AuthenticationClient>(() => AuthenticationClient());
Warning: Erik made a very good point in the comment below that the same type name can exist in multiple packages and that will cause issues. As much as I dislike to force the user to pass in a string key (that way it's the consumer's responsibility to ensuring the uniqueness of the type name), that might be the only way.
Admittedly, this is a little bit of an odd test case, but it's a problem I've ran in to. I have a class that takes a function as a parameter in it's constructor. I'd like to know if the function that was passed was called. Here's an example:
class TestClassMock extends Mock implements RealClass {
RealClass _real;
TestClassMock() {
_real = new RealClass();
when(callsTo("myNamedFunction")).alwaysCall(_real.myNamedFunction);
}
}
class RealClass {
String _name = "RealClass";
Function myNamedFunction;
RealClass() {
myNamedFunction = _theNamedFunction;
}
String _theNamedFunction() {
return _name;
}
}
class ClassThatCallsRealClass {
ClassThatCallsRealClass(Function func) {
func();
}
}
//The test
TestClassMock testClassMock = new TestClassMock();
ClassThatCallsRealClass caller = new ClassThatCallsRealClass(testClassMock.myNamedFunction);
testClassMock.getLogs(callsTo("myNamedFunction")).verify(happenedOnce);
So to explain a bit, ClassThatCallsRealClass takes a function as a parameter and calls it. If you were to pass in (Instance Of RealClass).myNamedFunction, this would in turn call the private function _theNamedFunction on RealClass. However, if you try to mock RealClass and redirect all calls from myNamedFunction to the RealClass myNamedFunction, this seems to fail. I don't see any clear way to get this to work, but I would think it'd be possible.
Any ideas?
In Dart, all functions are instances of class Function as you know since you pass an instance of Function to the ClassThatCallsRealClass constructor. Instances of Function have a method call() as shown here.
Meanwhile, Dart has a very good mocking capability described here (with thanks to #KWalrath for the update).
So all you need to do is test with mocks like with any other object. Just as described in the reference, create a spy for ClassThatCallsRealClass and a mock for your Function instance. Then use a verify(happenedOnce) on the call() method of the function.
To mock your function do this:
class MockFunction extends Mock {
call(int a, int b) => a + b;
}
var mock = new MockFunction();
mock(1,2); //returns 3
Of course the parameter list to call will match that of the real function. Pass mock to your spy on ClassThatCallsRealClass.
That worked for me:
library x;
import "package:unittest/unittest.dart";
import "package:unittest/mock.dart";
class TestClassMock extends Mock implements RealClass {
RealClass _real;
TestClassMock() {
_real = new RealClass();
when(callsTo("myNamedFunction")).alwaysCall(_real.myNamedFunction);
}
}
class RealClass {
String _name = "RealClass";
Function myNamedFunction;
RealClass() {
myNamedFunction = _theNamedFunction;
}
String _theNamedFunction() {
return _name;
}
}
class ClassThatCallsRealClass {
ClassThatCallsRealClass(Function func) {
func();
}
}
class MyFunc implements Function {
Function func;
String functionName;
MyFunc(this.func, this.functionName);
call() {
var inv = new MyInvocation(functionName);
func(inv);
}
}
main(List<String> args) {
test('xx', () {
//The test
TestClassMock testClassMock = new TestClassMock();
ClassThatCallsRealClass caller = new ClassThatCallsRealClass(new MyFunc(testClassMock.noSuchMethod, "myNamedFunction"));
testClassMock.getLogs(callsTo("myNamedFunction")).verify(happenedOnce);
});
}
class MyInvocation extends Invocation {
final String f;
MyInvocation(this.f);
bool get isGetter => false;
bool get isMethod => true;
bool get isSetter => false;
Symbol get memberName => new Symbol(f);
Map<Symbol, dynamic> get namedArguments => {};
List get positionalArguments => [];
}
testClassMock.myNamedFunction returns null so I call noSuchMethod directly instead which needs an Invocation.
Invocation is abstract so I created an implemented.
MyFunc is a class that wraps the function. MyFunc can be called as a function because it implements the call method.
The following code
class MemberException extends ServerException {
String message;
MemberException(message) {
super(message);
}
}
class ServerException implements Exception {
String message;
ServerException(this.message);
}
produces the following (somewhat unhelpful) error message
Too few arguments in implicit super() constructor invocation in '(String) -> dynamic'
The correct format is:
class MemberException extends ServerException {
String message;
MemberException(message) : super(message) {
// constructor body
}
}
You need to initialize super before the constructor body is called.
Ref: http://www.dartlang.org/docs/dart-up-and-running/contents/ch02.html#ch02-constructors (see the part on initializers)