Accept object as an function - dart

Is there any way in Dart to accept an object as a function?
I am looking for some operator or type that can replace +/*()=>*/ with some other operator without changing the expected functionality if that those operators would have not been commented
For example:
class Test {
operator +([...])=>[...];
}
void main() {
Test test = Test();
int a = 3;
var func = test + /*()=>*/ a;
print(func()); // should print 3
++a;
print(func()); // should print 4
}

Related

type safe create Lua tables in Haxe without runtime overhead and without boilerplate

I am trying to write some externs to some Lua libraries that require to pass dictionary tables and I want to make them type safe.
So far, I have been declaring abstract classes with public inline constructors, but this gets tedious really fast:
abstract JobOpts(Table<String, Dynamic>) {
public inline function new(command:String, args:Array<String>) {
this = Table.create(null, {
command: command,
arguments: Table.create(args)
});
}
}
Is there a better way that allows me to keep things properly typed but that does not require that much boilerplate?
Please note that typedefs and anonymous structures are not valid options, because they introduce nasty fields in the created table and also do a function execution to assign a metatable to them:
--typedef X = {cmd: String}
_hx_o({__fields__={cmd=true},cmd="Yo"})
My abstract code example compiles to a clean lua table, but it is a lot of boilerplate
Some targets support #:nativeGen to strip Haxe-specific metadata from objects, but this does not seem to be the case for typedefs on Lua target. Fortunately, Haxe has a robust macro system so you can make the code write itself. Say,
Test.hx:
import lua.Table;
class Test {
public static function main() {
var q = new JobOpts("cmd", ["a", "b"]);
Sys.println(q);
}
}
#:build(TableBuilder.build())
abstract JobOpts(Table<String, Dynamic>) {
extern public inline function new(command:String, args:Array<String>) this = throw "no macro!";
}
TableBuilder.hx:
import haxe.macro.Context;
import haxe.macro.Expr;
class TableBuilder {
public static macro function build():Array<Field> {
var fields = Context.getBuildFields();
for (field in fields) {
if (field.name != "_new") continue; // look for new()
var f = switch (field.kind) { // ... that's a function
case FFun(_f): _f;
default: continue;
}
// abstract "constructors" transform `this = val;`
// into `{ var this; this = val; return this; }`
var val = switch (f.expr.expr) {
case EBlock([_decl, macro this = $x, _ret]): x;
default: continue;
}
//
var objFields:Array<ObjectField> = [];
for (arg in f.args) {
var expr = macro $i{arg.name};
if (arg.type.match(TPath({ name: "Array", pack: [] } ))) {
// if the argument's an array, make an unwrapper for it
expr = macro lua.Table.create($expr, null);
}
objFields.push({ field: arg.name, expr: expr });
}
var objExpr:Expr = { expr: EObjectDecl(objFields), pos: Context.currentPos() };
val.expr = (macro lua.Table.create(null, $objExpr)).expr;
}
return fields;
}
}
And thus...
Test.main = function()
local this1 = ({command = "cmd", args = ({"a","b"})});
local q = this1;
_G.print(Std.string(q));
end
Do note, however, that Table.create is a bit of a risky function - you will only be able to pass in array literals, not variables containing arrays. This can be remedied by making a separate "constructor" function with the same logic but without array➜Table.create unwrapping.

dart nullability checking method [duplicate]

This question already has answers here:
"The operator can’t be unconditionally invoked because the receiver can be null" error after migrating to Dart null-safety
(3 answers)
Closed 12 months ago.
I have migrated my Dart code to NNBD / Null Safety. Some of it looks like this:
class Foo {
String? _a;
void foo() {
if (_a != null) {
_a += 'a';
}
}
}
class Bar {
Bar() {
_a = 'a';
}
String _a;
}
This causes two analysis errors. For _a += 'a';:
An expression whose value can be 'null' must be null-checked before it can be dereferenced.
Try checking that the value isn't 'null' before dereferencing it.
For Bar() {:
Non-nullable instance field '_a' must be initialized.
Try adding an initializer expression, or add a field initializer in this constructor, or mark it 'late'.
In both cases I have already done exactly what the error suggests! What's up with that?
I'm using Dart 2.12.0-133.2.beta (Tue Dec 15).
Edit: I found this page which says:
The analyzer can’t model the flow of your whole application, so it can’t predict the values of global variables or class fields.
But that doesn't make sense to me - there's only one possible flow control path from if (_a != null) to _a += 'a'; in this case - there's no async code and Dart is single-threaded - so it doesn't matter that _a isn't local.
And the error message for Bar() explicitly states the possibility of initialising the field in the constructor.
The problem is that class fields can be overridden even if it is marked as final. The following example illustrates the problem:
class A {
final String? text = 'hello';
String? getText() {
if (text != null) {
return text;
} else {
return 'WAS NULL!';
}
}
}
class B extends A {
bool first = true;
#override
String? get text {
if (first) {
first = false;
return 'world';
} else {
return null;
}
}
}
void main() {
print(A().getText()); // hello
print(B().getText()); // null
}
The B class overrides the text final field so it returns a value the first time it is asked but returns null after this. You cannot write your A class in such a way that you can prevent this form of overrides from being allowed.
So we cannot change the return value of getText from String? to String even if it looks like we checks the text field for null before returning it.
An expression whose value can be 'null' must be null-checked before it can be dereferenced. Try checking that the value isn't 'null' before dereferencing it.
It seems like this really does only work for local variables. This code has no errors:
class Foo {
String? _a;
void foo() {
final a = _a;
if (a != null) {
a += 'a';
_a = a;
}
}
}
It kind of sucks though. My code is now filled with code that just copies class members to local variables and back again. :-/
Non-nullable instance field '_a' must be initialized. Try adding an initializer expression, or add a field initializer in this constructor, or mark it 'late'.
Ah so it turns out a "field initializer" is actually like this:
class Bar {
Bar() : _a = 'a';
String _a;
}
There are few ways to deal with this situation. I've given a detailed answer here so I'm only writing the solutions from it:
Use local variable (Recommended)
void foo() {
var a = this.a; // <-- Local variable
if (a != null) {
a += 'a';
this.a = a;
}
}
Use ??
void foo() {
var a = (this.a ?? '') + 'a';
this.a = a;
}
Use Bang operator (!)
You should only use this solution when you're 100% sure that the variable (a) is not null at the time you're using it.
void foo() {
a = a! + 'a'; // <-- Bang operator
}
To answer your second question:
Non-nullable fields should always be initialized. There are generally three ways of initializing them:
In the declaration:
class Bar {
String a = 'a';
}
In the initializing formal
class Bar {
String a;
Bar({required this.a});
}
In the initializer list:
class Bar {
String a;
Bar(String b) : a = b;
}
You can create your classes in null-safety like this
class JobDoc {
File? docCam1;
File? docCam2;
File? docBarcode;
File? docSignature;
JobDoc({this.docCam1, this.docCam2, this.docBarcode, this.docSignature});
JobDoc.fromJson(Map<String, dynamic> json) {
docCam1 = json['docCam1'] ?? null;
docCam2 = json['docCam2'] ?? null;
docBarcode = json['docBarcode'] ?? null;
docSignature = json['docSignature'] ?? null;
}
}

How to assert objects by its state (all properties values) in a Dart unit test?

I have a class (with more properties than the example, of course).
How to write the following simple test? I know that equality in Dart is by object instance. How to compare the full object state? I tested with the same matcher as well, with no luck.
import 'package:test/test.dart';
class UnderTesting {
var a;
var b;
UnderTesting({this.a, this.b});
}
void main() {
test("compare objects", () {
final obj1 = UnderTesting(a:1, b:2);
final obj2 = UnderTesting(a:1, b:2);
// Next will fail because it is checking if it is the same instance
expect(obj1, equals(obj2));
} );
}
You need to override the == operator (and should therefore also override hashCode) for UnderTesting. The documentation for equals tells us how to does test for equality:
If [expected] is a [Matcher], then it matches using that. Otherwise it tests for equality using == on the expected value.
So you code should be something like this:
import 'package:test/test.dart';
import 'package:quiver/core.dart';
class UnderTesting {
int a;
int b;
UnderTesting({this.a, this.b});
#override
bool operator ==(Object other) =>
(other is UnderTesting) ? (a == other.a && b == other.b) : false;
#override
int get hashCode => hash2(a, b);
}
void main() {
test("compare objects", () {
final obj1 = UnderTesting(a: 1, b: 2);
final obj2 = UnderTesting(a: 1, b: 2);
expect(obj1, equals(obj2)); // All tests passed!
});
}
I can recommend the quiver package for making easy hashCode implementations: https://pub.dev/documentation/quiver/latest/quiver.core/quiver.core-library.html

'is' statement with a variable type

I want to check, if my variable k has a type calles T.
My approach was
int k=1;
Type T=int;
if(k is T) print('same type');
But it is not working. It works, if I write
if(k is int)
but I want to change the type in a variable.
Thank you for an answer
You could store the type in a string, and then use runtimeType and toString() to compare the variable's type with the type stored in the string:
int k = 1;
String type = "int";
if (k.runtimeType.toString() == type){
print("k is an integer");
}
You can't do type checks using Type objects in Dart.
A Type object is not the type, it's just a token representing the type which can be used with the dart:mirrorsreflection library. It cannot, really, be used for anything else.
If you need to do type checking, you need to store the type as a type variable, which means you need something generic, or store it in plain code as a closure.
The closure approach is simpler, but less readable:
int k = 1;
var typeChecker = (o) => o is int;
if (typeChecker(o)) print("k has the right type");
Using a generic helper class is more general:
class Typer<T> {
bool isType(Object o) => o is T;
bool operator >=(Typer other) => other is Typer<T>;
bool operator <=(Typer other) => other >= this;
}
...
var k = 1;
var type = Typer<int>();
if (type.isType(k)) print("k is integer");
In short, don't use Type for anything except dart:mirrors because it isn't really useful for anything else.
Some Type in the Dart returns a different kind of Type when using .runtimeType.
For example:
void main() async {
List value = [];
print(value.runtimeType); // print -> JSArray<dynamic>
}
I am using:
void main() async {
List value = [];
print(isSameType(target: value, reference: <Object>[])); // print -> false
value = [Object()];
print(isSameType(target: value, reference: <Object>[])); // print -> false
value = <Object>[];
print(isSameType(target: value, reference: <Object>[])); // print -> true
}
bool isSameType({required target, required reference}) =>
target.runtimeType == reference.runtimeType;
class Object {}
But I saw many comments saying the .runtimeType is for debugging and some comments said it will be not available in the future. So I am using this instead of the code above:
void main() async {
var value;
value = [];
print(value.runtimeType); // print -> JSArray<dynamic>
print(isSameType<List>(value)); // print -> true
value = [Test];
print(value.runtimeType); // print -> JSArray<Type>
print(isSameType<List<Test>>(value)); // print -> false
print(isSameType<List>(value)); // print -> true
value = [Test()];
print(value.runtimeType); // print -> JSArray<Test>
print(isSameType<List<Test>>(value)); // print -> true
print(isSameType<List>(value)); // print -> true
value = <Test>[];
print(value.runtimeType); // print -> JSArray<Test>
print(isSameType<List<Test>>(value)); // print -> true
print(isSameType<List>(value)); // print -> true
}
bool isSameType<type>(target) => target is type;
class Test {}
Basic example for using:
void main() async {
MyObject phoneNumber = MyObject<int>();
phoneNumber = await getDataFromUser();
if (phoneNumber.isSameType()) await uploadData(phoneNumber);
}
class MyObject<type> {
MyObject({this.data});
dynamic data;
bool isSameType() => data is type;
}
Future<dynamic> getDataFromUser() async {
return null;
}
Future<bool> uploadData(data) async {
return false;
}

Assign function/method to variable in Dart

Does Dart support the concept of variable functions/methods? So to call a method by its name stored in a variable.
For example in PHP this can be done not only for methods:
// With functions...
function foo()
{
echo 'Running foo...';
}
$function = 'foo';
$function();
// With classes...
public static function factory($view)
{
$class = 'View_' . ucfirst($view);
return new $class();
}
I did not found it in the language tour or API. Are others ways to do something like this?
To store the name of a function in variable and call it later you will have to wait until reflection arrives in Dart (or get creative with noSuchMethod). You can however store functions directly in variables like in JavaScript
main() {
var f = (String s) => print(s);
f("hello world");
}
and even inline them, which come in handy if you are doing recusion:
main() {
g(int i) {
if(i > 0) {
print("$i is larger than zero");
g(i-1);
} else {
print("zero or negative");
}
}
g(10);
}
The functions stored can then be passed around to other functions
main() {
var function;
function = (String s) => print(s);
doWork(function);
}
doWork(f(String s)) {
f("hello world");
}
I may not be the best explainer but you may consider this example to have a wider scope of the assigning functions to a variable and also using a closure function as a parameter of a function.
void main() {
// a closure function assigned to a variable.
var fun = (int) => (int * 2);
// a variable which is assigned with the function which is written below
var newFuncResult = newFunc(9, fun);
print(x); // Output: 27
}
//Below is a function with two parameter (1st one as int) (2nd as a closure function)
int newFunc(int a, fun) {
int x = a;
int y = fun(x);
return x + y;
}

Resources