I may be doing something wrong syntactically or practically so "don't do that" could be valid but it seems this should work:
class Thing {
//static dynamic noop = () { }; // fails
static dynamic noop = ([dynamic value]) { }; // works for null cases
dynamic _callback;
Thing._([dynamic callback([dynamic value])])
: this._callback = callback != null ? callback : Thing.noop;
factory Thing([dynamic callback([dynamic value])]) {
return new Thing._(callback);
}
}
When I run these tests, the first one fails but the second, third and fourth pass:
//Caught type '() => dynamic' is not a subtype of type '([dynamic]) => dynamic' of 'callback'.
test('callback with optional param', () {
var thing = new Thing(() { });
thing.doCallback();
thing.doCallback('data');
});
test('callback with optional param', () {
var thing = new Thing(([_]) { });
thing.doCallback();
thing.doCallback('data');
});
test('callback with optional param', () {
var thing = new Thing();
thing.doCallback();
thing.doCallback('data');
});
test('callback with optional param', () {
var thing = new Thing(null);
thing.doCallback();
thing.doCallback('data');
});
dynamic callback([dynamic value]) means a callback that can take one parameter or none. In your first test case, the callback you provides (() { }) only handles calls with no parameter. So it does not respect the contract. That's why you get this error.
Related
I have current function
public static ICacheManager GetCacheManager(string cacheManagerName, TimeSpan? expiration)
{
var cacheManager = CacheManagers.GetOrAdd(cacheManagerName, keyName =>
{
var ret = ServiceLocator.Current.GetInstance<ICacheManager>();
if (expiration.HasValue)
{
ret.Configure(keyName, expiration.Value);
}
else
{
ret.Configure(keyName);
}
return ret;
});
return cacheManager;
}
JetBrains Rider says there is
Closure allocation: 'keyName' parameter + (outer closure of 'expiration' parameter)
Well, I know there is override
GetOrAdd<TArg>(TKey, Func<TKey,TArg,TValue>, TArg)
but how to use it?
How to rewrite this function to avoid closure and pass another parameters to lambda function? What if I need to pass multiple parameters (db query etc.)
This is how you use TArg overload:
concurrentDictionary.GetOrAdd(key, (k, v) => {
//do your thing, "v" will be "someVariable"
}, someVariable);
So in your case it will be
CacheManagers.GetOrAdd(cacheManagerName, (keyName, v) =>
{
var ret = ServiceLocator.Current.GetInstance<ICacheManager>();
if (v.HasValue)
{
ret.Configure(keyName, v.Value);
}
else
{
ret.Configure(keyName);
}
return ret;
}, expiration);
This overload - GetOrAdd<TArg>(TKey, Func<TKey,TArg,TValue>, TArg) - simply allows to pass stuff to the factory.
This is what I want to implement:
void fun({
bool Function(int i) predicate = (i) => false,
}) {
// do something with 'predicate(something)'
}
But I am getting the error:
The default value of an optional parameter must be constant.dart(non_constant_default_value).
I was able to get arround this error with the following:
bool falsePredicate(int i) => false;
void fun({
bool Function(int i) predicate = falsePredicate,
}) {
// do something with 'predicate(something)'
}
But now the question becomes, why can't I directly create a default function value as in the first set of code? There seems to be no difference between the first and the second cases. How is the function given in the first approach not constant?
As #Noah has pointed to the git discussion, the dart language has this missing piece of compile-time constant functions, which eventually leads to this problem.
Check this post: https://github.com/dart-lang/language/issues/1048
As the post shows, the issue has been raised in mid-2012 and now it's been 8+ years. So the hopes of this being available in the near feature is very less.
However few alternative solutions till then:
Option 1 (separate method):
class ServiceProvider {
static bool falsePredicate(int i) => false;
void fun({
bool Function(int i) predicate = falsePredicate,
}) {
// do something with 'predicate(something)'
}
}
Option 2 (Null checking while using the predicate)
class ServiceProvider {
void fun({
bool Function(int i)? predicate,
}) {
int val = 55; // for demonstration
predicate?.call(val); // Call only if the predicate is non-null
}
}
Option 3 (Only for class constructors)
class ServiceProvider {
final bool Function(int i) _predicate;
ServiceProvider ({bool Function(int i)? predicate})
: _predicate = predicate ?? ((i) => false);
void fun() {
int val = 55;
_predicate(5); // No null check is needed. The predicate is always non-null
}
}
With the below code as an example I can not figure out how to make the generic typed Function work with out casting as shown. Every other way I try I get some variation of
The argument type 'Null Function(Gift)' can't be assigned to the
parameter type 'dynamic Function(T)'
var present = Present<Gift>(Gift('Fancy Gift'), <T>(Gift t) {
print('${(t as Gift).name} was opened.');
});
or
The getter 'name' isn't defined for the type 'Object'
var present = Present<Gift>(Gift('Fancy Gift'), <Gift>(t) {
print('${t.name} was opened.');
});
Here is the working example with a cast.
void main() {
var present = Present<Gift>(Gift('Fancy Gift'), <T>(t) {
print('${(t as Gift).name} was opened.');
});
present.open();
}
class Present<T> {
final T _item;
final Function<T>(T t) openedCallback;
T open() {
openedCallback.call(_item);
return _item;
}
Present(this._item, this.openedCallback);
}
class Gift {
final String name;
Gift(this.name);
}
There should be a way to do this without a cast right?
Your class definition does not do what you intend:
class Present<T> {
final T _item;
final Function<T>(T t) openedCallback;
...
openedCallback is separately parameterized; its T type parameter is separate and independent from that of Present<T>. There is no need to parameterize openedCallback since you presumably want:
class Present<T> {
final T _item;
final Function(T t) openedCallback;
...
After that, you can do:
var present = Present<Gift>(Gift('Fancy Gift'), (t) {
print('${t.name} was opened.');
});
Note that doing <T>(t) { ... } or <Gift>(t) { ... } is counterproductive. That declares an anonymous function that itself is generic and is has a type parameter named T or Gift respectively.
This is my code:
var badget = function () {
var privetVar = 23;
var privetFunc = function (a) {
return privetVar + a;
}
return {
publicFunc: function (b) {
console.log(privetFunc (b));
}
}
}();
It works well; I have access to the publicFunc() using badget.publicFunc(), which has access to the privetVar and privetFunc() due to "closures".
However, someone told me I must use parentheses like this:
var badget = (function() {
var privetVar = 23;
var privetFunc = function(a) {
return privetVar + a;
}
return {
publicFunc: function(b) {
console.log(privetFunc(b));
}
}
})();
Is this second example considered a preferable syntax?
No, the parentheses are not required in this example. Typically people don't use the return value of an IIFE, so the parentheses are required to differentiate a function expression from a function statement.
Since your function declaration in your first example is already part of an assignment expression, it's already a function expression, so the parentheses aren't required.
TL;DR
Valid
var badget = function () {
...
}();
(function () {
...
})();
(function () {
...
}());
Valid (but not necessary)
var badget = (function () {
...
})();
var badget = (function () {
...
}());
Invalid (function statements cannot be IIFEs)
function () {
...
}();
I have the following code (simplified), that uses reflection to iterate a class's fields and getters and output the values. The ContainsGetter class contains a getter, and the ContainsField class contains a simple field.
Using dart:mirrors library, I can get the value of the field by using instanceMirror.getField(fieldName)), but not the getter by using instanceMirror.invoke(fieldName,[]).
The following Dart script (using the build 17463) gives the output below:
app script
import 'dart:mirrors';
class ContainsGetter { // raises an error
String get aGetter => "I am a getter";
}
class ContainsField { // works fine
String aField = "I am a field";
}
void main() {
printFieldValues(reflect(new ContainsField()));
printGetterValues(reflect(new ContainsGetter()));
}
void printFieldValues(instanceMirror) {
var classMirror = instanceMirror.type;
classMirror.variables.keys.forEach((key) {
var futureField = instanceMirror.getField(key); // <-- works ok
futureField.then((imField) => print("Field: $key=${imField.reflectee}"));
});
}
void printGetterValues(instanceMirror) {
var classMirror = instanceMirror.type;
classMirror.getters.keys.forEach((key) {
var futureValue = instanceMirror.invoke(key,[]); // <-- fails
futureValue.then((imValue) => print("Field: $key=${imValue.reflectee}"));
});
}
output
Field: aField=I am a field
Uncaught Error: Compile-time error during mirrored execution: <Dart_Invoke: did not find instance method 'ContainsGetter.aGetter'.>
Stack Trace:
#0 _LocalObjectMirrorImpl._invoke (dart:mirrors-patch:163:3)
#1 _LocalObjectMirrorImpl.invoke (dart:mirrors-patch:125:33)
(An acceptable could be that "this bit just hasn't been written yet!")
Aah, I've just worked it out. Although aGetter is like a method in its implementation, you use the getField() rather than invoke to retrieve its value.
void printGetterValues(instanceMirror) {
var classMirror = instanceMirror.type;
classMirror.getters.keys.forEach((key) {
var futureValue = instanceMirror.getField(key); // <-- now works ok
futureValue.then((imValue) => print("Field: $key=${imValue.reflectee}"));
});
}