I'm able to do something like the following in TypeScript
class Foo {
private constructor () {}
}
so this constructor is accessible only from inside the class itself.
How to achieve the same functionality in Dart?
Just create a named constructor that starts with _
class Foo {
Foo._() {}
}
then the constructor Foo._() will be accessible only from its class (and library).
A method without any code must be something like this
class Foo {
Foo._();
}
Yes, It is possible, wanna add more information around it.
A constructor can be made private by using (_) underscore operator which means private in dart.
So a class can be declared as
class Foo {
Foo._() {}
}
so now, The class Foo doesn't have a default constructor
Foo foo = Foo(); // It will give compile time error
The same theory applied while extending class also, It's also impossible to call the private constructor if it declares in a separate file.
class FooBar extends Foo {
FooBar() : super._(); // This will give compile time error.
}
But both above functionality works if we use them in the same class or file respectively.
Foo foo = Foo._(); // It will work as calling from the same class
and
class FooBar extends Foo {
FooBar() : super._(); // This will work as both Foo and FooBar are declared in same file.
}
you can create following class in order to get a singleton instance
class Sample{
factory Sample() => _this ??= Sample._();
Sample._(); // you can add your custom code here
static Sample _this;
}
Now in the main function you can call the sample constructor
void main(){
/// this will return the _this instace from sample class
Sample sample = Sample();
}
just use abstract class.
Because you can't instantiate abstract class
Related
I can't understand why this code doesn't compile.
In my intentions, the following snippet should declare a BaseGenericClass with no constraint on its argument, and a GenericClass deriving from BaseGenericClass with a constraint on type T telling the compiler to accept only classes derived from AbstractArgClass.
abstract class BaseGenericClass<T> {
final T _arg;
BaseGenericClass(this._arg);
}
class GenericClass<T extends AbstractArgClass> extends BaseGenericClass<T> {
GenericClass() : super(ArgClass());
}
abstract class AbstractArgClass {}
class ArgClass extends AbstractArgClass {}
ArgClass derives from AbstractArgClass, still lines 8 raises this error:
The argument type 'ArgClass' can't be assigned to parameter type 'T'
I think the compiler is correct here. ArgClass and AbstractArgClass in fact do not extend T, and I can't see a way to tell them that T is meant to be ArgClass.
It should work if you change it like this:
class GenericClass<T extends AbstractArgClass> extends BaseGenericClass<T> {
GenericClass(T t) : super(t);
}
You have to supply your instance of ArgClass to the constructor of GenericClass:
final g = GenericClass(ArgClass());
If you do not want to provide this from ouside, you can add a static function to make a new instance, like:
class GenericClass<T extends AbstractArgClass> extends BaseGenericClass<T> {
GenericClass._(T t) : super(t);
static GenericClass make() => GenericClass._(ArgClass());
}
and get an instance:
final g = GenericClass.make();
Ber's answer apparently works around the problem introducing a sort of intermediation... I tried to create a useless IntermediateClass that just introduces the restrictions on the type T (T has to derive from AbstractArgClass). This works!!!
AnotherGenericClass, as expected, does not compile because AnotherClass does not extend AbstractArgClass.
Still the question: why?
It looks like a compiler glitch to me, do you agree?
abstract class BaseGenericClass<T> {
final T _arg;
BaseGenericClass(this._arg);
}
class IntermediateClass<T extends AbstractArgClass> extends BaseGenericClass<T> {
IntermediateClass(T arg) : super(arg);
}
class GenericClass extends IntermediateClass {
GenericClass() : super(ArgClass());
}
abstract class AbstractArgClass {}
class ArgClass extends AbstractArgClass {}
class AnotherClass {}
class AnotherGenericClass extends IntermediateClass {
AnotherGenericClass() : super(AnotherClass());
}
I want to invoke functions of a class by their names inside a string. I know my best option are Mirrors.
var ref = reflect(new TestClass());
ref.invoke(Symbol("test"), []);
It works fine, I can call the function test by a string. But I also want to put "TestClass" inside a string. Is it possible somehow ?
var ref = reflect("TestClass");
ref.invoke(Symbol("test"), []);
Jonas
You can do something like this:
import 'dart:mirrors';
class MyClass {
static void myMethod() {
print('Hello World');
}
}
void main() {
callStaticMethodOnClass('MyClass', 'myMethod'); // Hello World
}
void callStaticMethodOnClass(String className, String methodName) {
final classSymbol = Symbol(className);
final methodSymbol = Symbol(methodName);
(currentMirrorSystem().isolate.rootLibrary.declarations[classSymbol]
as ClassMirror)
.invoke(methodSymbol, <dynamic>[]);
}
Note, that this implementation does require that myMethod is static since we are never creating any object but only operate directly on the class itself. You can create new objects from the class by calling newInstance on the ClassMirror but you will then need to call the constructor.
But I hope this is enough. If not, please ask and I can try add some more examples.
I'm trying to bind a class C from a third-party's package.
It injects a class Foo instance via constructor -
class C {
public C(#Inject Foo foo) {
...
}
...
}
In my application, I've two instances of Foo bound -
bind(Foo.class)
.to(FooImpl1.class);
bind(Foo.class)
.annotatedWith(Names.named("SpecialFoo"))
.to(FooImpl2.class);
when C is bound, I want the Named Foo instance to be used. However I do not have access to the code in which C is defined, to be able to put any annotations.
Is there a suggested way of doing that, short of writing my own provider method for C?
You could look into using PrivateModule. In your example, it will be something like:
public class CModule extends PrivateModule {
protected void configure() {
bind(Foo.class).to(FooImpl2.class);
bind(C.class);
expose(C.class);
}
}
I have a class I want to use mostly as a base class for other classes that have constant instances, but also as a mixin class for others. Ideally, I'm after something like the following:
class Base{
someMethod(){
//do something
}
}
class ConstantClass extends Base{
const ConstantClass();
anotherMethod(){
//do something else
}
}
class MixedClass extends NonMixinClass with Base{
thirdMethod(){
//a third thing
}
}
The above has an error in that ConstantClass cannot have a constant constructor without calling a super-class constant constructor. However, if I add a constructor of any kind to Base(), it can't be used as a mixin.
My current workaround is to duplicate functionality in static methods, as in the following:
class Base{
const Base();
static someStaticMethod(Base base){
//do something
}
someMethod() => Base.someStaticMethod(this);
}
class ConstantClass extends Base{
const ConstantClass(): super();
anotherMethod(){
//do something else
}
}
class BaseMixin implements Base{
someMethod() => Base.someStaticMethod(this);
}
class MixedClass extends NonMixinClass with BaseMixin{
thirdMethod(){
//a third thing
}
}
This isn't too bad when there's only one function in the base class, but things get pretty verbose for a complex class, and if there's a simple way of getting around the problem I'd love to keep things clean. Thanks in advance.
I though class ConstantClass extends Object with Base { would do it, but the new error I get is "Constant constructor cannot be declared for a class with a mixin". So I don't see a solution here, but not using a const constructor.
A few times now I've run into a use case where I need to define an interface for how classes construct themselves. One such example could be if I want to make an Interface Class that defines the interface by which objects can serialize and unserialize themselves (for input into a database, to be sent as JSON, etc). You might write something like this:
abstract class Serializable {
String serialize();
Serializable unserialize(String serializedString);
}
But now you have a problem, as serialize() is properly an instance method, and unserialize() should instead be a static method (which isn't inheritable or enforced by the Interface) or a constructor (which also isn't inheritable).
This leaves a state where classes that impliment the Serializable interface are required to define a serialize() method, but there is no way to require those classes to define a static unserialize() method or Foo.fromSerializedString() constructor.
If you make unserialize() an instance method, then unserializing an implementing class Foo would look like:
Foo foo = new Foo();
foo = foo.unserialize(serializedString);
which is rather cumbersome and ugly.
The only other option I can think of is to add a comment in the Serializable interface asking nicely that implementing classes define the appropriate static method or constructor, but this is obviously prone to error if a developer misses it and also hurts code completion.
So, is there a better way to do this? Is there some pattern by which you can have an interface which forces implementing classes to define a way to construct themselves, or something that gives that general effect?
You will have to use instance methods if you want the inheritance guarantees. You can do a bit nicer than manual instantiation though, by using reflection.
abstract class Serializable {
static Serializable fromSerializedString(Type type, String serializedString) {
ClassMirror cm = reflectClass(type);
InstanceMirror im = cm.newInstance(const Symbol(''), []);
var obj = im.reflectee;
obj.unserialize(serializedString);
return obj;
}
String serialize();
void unserialize(String serializedString);
}
Now if someone implements Serializable they will be forced to provide an unserialize method:
class Foo implements Serializable {
#override
String serialize() {
// TODO: implement serialize
}
#override
void unserialize(String string) {
// TODO: implement unserialize
}
}
You can get an instance like so:
var foo = Serializable.fromSerializedString(Foo, 'someSerializedString');
This might be a bit prettier and natural than the manual method, but keep in mind that it uses reflection with all the problems that can entail.
If you decide to go with a static method and a warning comment instead, it might be helpful to also provide a custom Transformer that scans through all classes implementing Serializable and warn the user or stops the build if any don't have a corresponding static unserialize method or constructor (similar to how Polymer does things). This obviously wouldn't provide the instant feedback the an editor could with instance methods, but would be more visible than a simple comment in the docs.
I think this example is a more Dart-like way to implement the encoding and decoding. In practice I don't think "enforcing" the decode signature will actually help catch bugs, or improve code quality. If you need to make the decoder types pluggable then you can make the decoders map configurable.
const Map<String,Function> _decoders = const {
'foo': Foo.decode,
'bar': Bar.decode
};
Object decode(String s) {
var obj = JSON.decode(s);
var decoder = _decoders[obj['type']];
return decoder(s);
}
abstract class Encodable {
abstract String encode();
}
class Foo implements Encodable {
encode() { .. }
static Foo decode(String s) { .. }
}
class Bar implements Encodable {
encode() { .. }
static Foo decode(String s) { .. }
}
main() {
var foo = decode('{"type": "foo", "i": 42}');
var bar = decode('{"type": "bar", "k": 43}');
}
A possible pattern I've come up with is to create a Factory class that utilize instance methods in a slightly less awkward way. Something like follows:
typedef Constructable ConstructorFunction();
abstract class Constructable {
ConstructorFunction constructor;
}
abstract class Serializable {
String serialize();
Serializable unserialize(String serializedString);
}
abstract class SerializableModel implements Serializable, Constructable {
}
abstract class ModelFactory extends Model {
factory ModelFactory(ConstructorFunction constructor) {
return constructor();
}
factory ModelFactory.fromSerializedString(ConstructorFunction constructor, String serializedString) {
Serializable object = constructor();
return object.unserialize(serializedString);
}
}
and finally a concrete implementation:
class Foo extends SerializableModel {
//required by Constructable interface
ConstructorFunction constructor = () => new Foo();
//required by Serializable interface
String serialize() => "I'm a serialized string!";
Foo unserialize(String serializedString) {
Foo foo = new Foo();
//do unserialization work here to populate foo
return foo;
};
}
and now Foo (or anything that extends SerializableModel can be constructed with
Foo foo = new ModelFactory.fromSerializedString(Foo.constructor, serializedString);
The result of all this is that it enforces that every concrete class has a method which can create a new instance of itself from a serialized string, and there is also a common interface which allows that method to be called from a static context. It's still creating an extra object whose whole purpose is to switch from static to instance context, and then is thrown away, and there is a lot of other overhead as well, but at least all that ugliness is hidden from the user. Still, I'm not yet convinced that this is at all the best way to achieve this.
I suggest you define the unserialize function as named constructor like so:
abstract class Serializable<T> {
String serialize();
Serializable.unserialize(String serializedString);
}
This eliminates the need of static methods.
A possible implementation could look like this:
import 'dart:convert';
class JsonMap implements Serializable<JsonMap> {
Map map = {};
JsonMap() {
}
String serialize() {
return JSON.encode(map);
}
JsonMap.unserialize(String serializedString) {
this.map = JSON.decode(serializedString);
}
}
You can (de)serialize like so:
JsonMap m = new JsonMap();
m.map = { 'test': 1 };
print(m.serialize());
JsonMap n = new JsonMap.unserialize('{"hello": 1}');
print(n.map);
While testing this, I noticed that Dart will not throw any errors at you if you dont actually implement the methods that your class promises to implement with implements. This might just be a hicc-up with my local Dart, though.