In Dart, is it possible to upcast a generic function? - dart

I'll start with the code since I'm having a hard time describing this problem without it.
typedef Future<S> EventFunction<E extends Event, S extends State>(E event);
abstract class State { }
abstract class Event { }
class FooState extends State { }
class FooEvent extends Event { }
void main() {
withEvent(foo);
}
void withEvent(EventFunction func) { }
Future<FooState> foo(FooEvent event) { }
Seeing this code I assume that I'm allowed to call withEvent using any function that returns a Future with a type that extends State and any instance that inherits from Event. However, the compiler claims that they are not the same type, which they are not, but they are compatible. Is this a limitation in Dart itself or am I doing something wrong?
EDIT
In response to RĂ©mi who pointed out that I was defining withEventswrongly:
Defining withEvent as void withEvent<E extends Event, S extends State>(EventFunction<E, S> func) { } I am allowed to call it with the desired arguments, however, I am also allowed to call it with something like Future<FooState> bar(int event) which is undesirable as int does not extend Event.

The issue is in the definition of your withEvent function:
void withEvent(EventFunction func) { }
This doesn't do what you expect. It is equivalent to:
void withEvent(EventFunction<dynamic, dynamic> func) { }
You need to make withEvent generic too:
void withEvent<E extends Event, S extends State>(EventFunction<E, S> func) { }

Actually, what you are trying is correct and should works. The thing is, dart being type safe you'd have to specify generics arguments if a function type accepts any.
Here, your EventFunction event function accepts two generic type arguments which are missing at withEvent definition.
Just change your,
void withEvent(EventFunction func) { } // dart infers EventFunction = EventFunction<dynamic,dynamic> when no generic arguments passed
to,
void withEvent(EventFunction<FooEvent,FooState> func) { }
This should work. Hope it helps!

Related

NoSuchMethodEror: tried to call a non-function, such as null:

I have this code which works well on android emulator but gives error on web.
import 'package:parivaar/components/screens/home/Home.dart';
typedef T Constructor<T>();
final Map<String, Constructor<Object>> _constructors =
<String, Constructor<Object>>{};
void register<T>(Constructor<T> constructor) {
_constructors[T.toString()] = constructor;
}
class ClassBuilder {
static void registerClasses() {
register<Home>(() => Home());
}
static dynamic fromString(String type) {
return _constructors[type]();
}
}
And i am calling that function as follows:
class _MyHomePageState extends State {
KFDrawerController _drawerController;
#override
void initState() {
super.initState();
_drawerController = KFDrawerController(
initialPage: ClassBuilder.fromString('Home'),
.
..
...
....
You are probably assuming that T.toString() returns the source name of the type as a string. Nobody ever promised that.
It works on native, but on the web you often optimize for size and "minification" turns all the long names into shorter names. With that, the name of the type Home is no longer the string "Home".
I generally do not recommend depending on the string representation of types (or Type objects for that matter).
Consider changing register and fromString to:
void register<T>(Constructor<T> constructor) {
_constructors[T] = constructor;
}
and
static T fromType<T>() => _constructors[T]();
That relies on Type object equality, which is a well-defined operation.
Not perfect, but still better than going through strings.
If you need to create the objects dynamically from strings, where you don't know the type, then I'd instead require you to provide the key string on registration, changing register to:
void register<T>(String key, Constructor<T> constructor) {
_constructors[key] = constructor;
}
and register types like:
static void registerClasses() {
register<Home>("Home", () => Home());
}

Casting subtype fails

class A {
void hello() {
print('world');
}
}
class B extends A {
#override
void hello() {
print('StackOverflow');
}
}
(A() as B).hello(); results in type 'A' is not a subtype of type 'B' in type cast.
Full disclosure: I don't know Dart.
You can't do this kind of cast because it might result in function calls or field accesses that aren't well defined.
I'll change your example to demonstrate:
class A {
void hello() {
print('world');
}
}
class B extends A {
#override
void hello() {
print('StackOverflow');
}
void hello2() {
print('Is Great!');
}
}
Now if you do (A() as B).hello2(); what should Dart do? This isn't really obvious, so it doesn't allow you to do that. Going the other way isn't an issue since B inherits all stuff from A.
class A {
void hello() {
print('world');
}
}
class B extends A {
#override
void hello() {
print('StackOverflow');
}
}
class C extends A {
#override
void hello() {
print('Hello');
}
}
Another issue is a value that has type A may be a different subtype of A like C
The way casting works is you can only go from a more specific type, B in this case, to a more general type, A. Your creating an instance of A, but A is not B.
Dart generally allows you to down-cast from a super-type to a sub-type because the value might actually be of the sub-type.
Animal animal = Cat();
if (something) animal = Dog();
...
Cat cat = animal as Cat; // Allowed, the animal may be a cat.
However, Dart 2 disallows down-casts in a few cases where it is obvious (even to the compiler) that the cast will always fail at run-time. That's what you are hitting here: (A() as B). The A() calls a generative constructor, so the compiler knows that the type of that expressions is exactly A (and not any proper sub-type of A). So, it knows that casting that to B will always fail at run-time, and for your own protection, it disallows the program entirely. Hence, a compile-time error.

How to generate code for a XExpression subtype?

I have a simple DSL that should generate async code for expressions (this is the simplest example I could come up with to illustrate my point). I just added to the scripting example an new async statement:
grammar org.xtext.scripting.Scripting with org.eclipse.xtext.xbase.Xbase
generate scripting "http://www.xtext.org/scripting/Scripting"
import "http://www.eclipse.org/xtext/xbase/Xbase" as xbase
Script returns xbase::XBlockExpression:
{Script}
(expressions+=XExpressionOrVarDeclaration ';'?)*;
XExpression returns xbase::XExpression:
super | Async
;
Async:
'async' expression=XExpression
;
The idea would be that the async code is executed in another thread.
My question is, how can I generate code for the Async.expression using the ScriptingJvmModelInferrer?
In the simplest case I would just wrap the code from the Async.expression like this?
AsyncRunner.exec(new Runnable() {
#Override
public void run() {
// the Async.expression would end up here
}
})
Where is the hook to do that?
You have to make 3 changes:
Extend the compiler to deal with your language. The key point is to handle the Async expression.
class ScriptingCompiler extends XbaseCompiler {
override protected doInternalToJavaStatement(XExpression expr, ITreeAppendable it, boolean isReferenced) {
switch expr {
Async : {
newLine
append('''
AsyncRunner.exec(new Runnable() {
#Override
public void run() {''')
expr.expression.doInternalToJavaStatement(it, false)
newLine
append('}});')
}
default :
super.doInternalToJavaStatement(expr, it, isReferenced)
}
}
override protected internalToConvertedExpression(XExpression obj, ITreeAppendable it) {
if (hasName(obj))
append(getName(obj))
else
super.internalToConvertedExpression(obj, it)
}
}
The type of the expression has to be specified
class ScriptingTypeComputer extends XbaseWithAnnotationsTypeComputer {
override computeTypes(XExpression expression, ITypeComputationState state) {
if(expression instanceof Async) {
super.computeTypes(expression.expression, state);
} else {
super.computeTypes(expression, state)
}
}
}
Both extensions have to be injected:
class ScriptingRuntimeModule extends AbstractScriptingRuntimeModule {
def Class<? extends XbaseCompiler> bindXbaseCompiler() {
return ScriptingCompiler
}
def Class<? extends ITypeComputer> bindITypeComputer() {
return ScriptingTypeComputer
}
}
If you extend Xbase you ususally don't apapt the JvmModelInferrer for Compilation but you extend XbaseTypeComputer and XbaseCompiler.doInternalToJavaStatement/internalToConvertedExpression (depending on what you actually introduce)

#override of Dart code

I noticed PetitParserDart has a lot of #override in the code, but I don't know how do they be checked?
I tried IDEA dart-plugin for #override, but it has no effect at all. How can we use #override with Dart?
From #override doc :
An annotation used to mark an instance member (method, field, getter or setter) as overriding an inherited class member. Tools can use this annotation to provide a warning if there is no overridden member.
So, it depends on the tool you use.
In the current Dart Editor(r24275), there's no warning for the following code but it should (it looks like a bug).
import 'package:meta/meta.dart';
class A {
m1() {}
}
class B extends A {
#override m1() {} // no warning because A has a m1()
#override m2() {} // tools should display a warning because A has no m2()
}
The #override annotation is an example of metadata. You can use Mirrors to check for these in code. Here is a simple example that checks if the m1() method in the child class has the #override annotation:
import 'package:meta/meta.dart';
import 'dart:mirrors';
class A {
m1() {}
}
class B extends A {
#override m1() {}
}
void main() {
ClassMirror classMirror = reflectClass(B);
MethodMirror methodMirror = classMirror.methods[const Symbol('m1')];
InstanceMirror instanceMirror = methodMirror.metadata.first;
print(instanceMirror.reflectee); // Instance of '_Override#0x2fa0dc31'
}
it's 2021 . the override it's optional
Use the #override annotation judiciously and only for methods where the superclass is not under the programmer's control, the superclass is in a different library or package, and it is not considered stable. In any case, the use of #override is optional. from dart api https://api.dart.dev/stable/2.10.5/dart-core/override-constant.html
example
Class A {
void say (){
print ('Say something 1') ;
}
}
Class B extends A {
#override
void adds() { // when i don't type the same name of super class function show an
// warning not an error say 'The method doesn't override an inherited
// method.' because it's not same name but when type the same name must be
// overriding
print ('Say something 2 ')
}
Update : the main use of #override is when try to reach abstract method inside abstract class in sub class that inherited to the abstract super class . must use #override to access the abstract method .

Accessing public variables from inside ccTouchesBegan method in cocos2d-x

I'm having little trouble accessing public ivars form the ccTouchesBegan method,
I have this Scene:
class introScene : public cocos2d::CCLayer {
public:
virtual bool init();
static cocos2d::CCScene* scene();
bool autoScroll;
virtual void ccTouchesBegan(cocos2d::CCSet* touches, cocos2d::CCEvent* event);
void skip();
CREATE_FUNC(introScene);
};
and from inside the .cpp file I try to access the variable autoScroll, but it insists that the variable doesn't exist, am I doing anything wrong here ??
void ccTouchesBegan(cocos2d::CCSet* touches, cocos2d::CCEvent* event){
autoScroll = false;
}
This generates: use of undeclared identifier 'autoScroll'
I don't know anything about cocos2d, but I reckon you've defined the method incorrectly as you've missed off the class name. Try this:
void introScene::ccTouchesBegan(cocos2d::CCSet* touches, cocos2d::CCEvent* event){
// ^^^^^^^
autoScroll = false;
}

Resources