I'm new to Dart and just learning the basics.
The Dart-Homepage shows following:
It turns out that Dart does indeed have a way to ask if an optional
parameter was provided when the method was called. Just use the
question mark parameter syntax.
Here is an example:
void alignDingleArm(num axis, [num rotations]) {
if (?rotations) {
// the parameter was really used
}
}
So I've wrote a simple testing script for learning:
import 'dart:html';
void main() {
String showLine(String string, {String printBefore : "Line: ", String printAfter}){
// check, if parameter was set manually:
if(?printBefore){
// check, if parameter was set to null
if(printBefore == null){
printBefore = "";
}
}
String line = printBefore + string + printAfter;
output.appendText(line);
output.appendHtml("<br />\n");
return line;
}
showLine("Hallo Welt!",printBefore: null);
}
The Dart-Editor already marks the questionmark as Error:
Multiple markers at this line
- Unexpected token '?'
- Conditions must have a static type of
'bool'
When running the script in Dartium, the JS-Console shows folloing Error:
Internal error: 'http://localhost:8081/main.dart': error: line 7 pos 8: unexpected token '?'
if(?printBefore){
^
I know, that it would be enough to check if printBefore is null, but I want to learn the language.
Does anyone know the reason for this problem?
How to check, if the parameter is set manually?
The feature existed at some point in Dart's development, but it was removed again because it caused more complication than it removed, without solving the problem that actually needed solving - forwarding of default parameters.
If you have a function foo([x = 42]) and you want a function to forward to it, bar([x]) => f(x);, then, since foo could actually tell if x is passed or not, you actually ended up writing bar([x]) => ?x ? foo(x) : foo();. That was worse than what you had to do without the ?: operator.
Ideas came up about having a bar([x]) => foo(?:x) or something which pased on x if it was present and not if it was absent (I no longer remember the actual proposed syntax), but that got complicated fast, fx converting named arguments to positional - bar({x,y}) => foo(?:x, ?:y); - what if y was provided and x was not. It was really just a bad solution for a self-inflicted problem.
So, the ?x feature was rolled back. All optional parameters have a default value which is passed if there is no matching argument in a call. If you want to forward an optional parameter, you need to know the default value of the function you are forwarding to.
For most function arguments, the declared default value is null, with an internal if (arg == null) arg = defaultValue; statement to fix it. That means that the null value can be forwarded directly without any confusion.
Some arguments have a non-null default value. It's mostly boolean arguments, but there are other cases too. I recommend using null for everything except named boolean parameters (because they are really meant to be named more than they are meant to be optional). At least unless there is a good reason not to - like ensuring that all subclasses will have the same default value for a method parameter (which may be a good reason, or not, and should be used judiciosuly).
If you have an optional parameter that can also accept null as a value ... consider whether it should really be optional, or if you just need a different function with one more argument. Or maybe you can introduce a different "missing argument" default value. Example:
abstract class C { foo([D something]); }
class _DMarker implements D { const _DMarker(); }
class _ActualC {
foo([D something = const _DMarker()]) {
if (something == const _DMarker()) {
// No argument passed, because user cannot create a _DMarker.
} else {
// Argument passed, may be null.
}
}
}
This is a big workaround, and hardly ever worth it. In general, just use null as default value, it's simpler.
I was trying something similar:
This does not work
widget.optionalStringParameter ? widget.optionalStringParameter : 'default string'
This works
widget.optionalStringParameter != null ? widget.optionalStringParameter : 'default string'
This also works
widget.optionalStringParameter ?? 'default string'
There was support for checking if an optional parameter was actually provider in early Dart days (pre 1.0) but was removed because it causes some troubles.
Related
I'm rewriting a framework from Perl5 to Perl6 for my work purposes. At some place I need to collect information from other modules/classes by executing a public sub they might provide; or they may not. So, it necessary to find out if the sub is present. This is not a big deal when a module is referenced directly (Foo::<&my-sub>) or by a symbolic name in a string (&::("Foo")::my-sub). But for the simplicity of it I would like to allow to pass module names as-is (lets say collector is the method collecting the info):
self.collector( Foo );
Where Foo could be the following:
module Foo {
use Bar;
use Baz;
our sub my-sub { Bar, 'Baz' }
}
And this is where I'm missing something important from Perl6 syntax because the following:
method collector ( $mod ) {
my $mod-name = $mod.WHO;
my #mods;
with &::($mod-name)::my-sub {
#mods.push: &$_();
}
}
is currently the only way I can perform the task.
I didn't try a type capture yet though. Should work as expected, I guess. So, the question is more about extending my knowelge of the syntax.
The final solution from the exchange with Vadim in the comments on their question. It's arguably insane. They think it's beautiful. And who am I to argue? .oO( Haha, hoho, heehee... )
my $pkg-arg = (Int, 'Int').pick;
my \pkg-sym = $pkg-arg && ::($pkg-arg);
my \sub-ref = &pkg-sym::($subname);
There are two obviously useful ways to refer to a package:
Its symbolic name. Int is the symbolic name of the Int class.
Its string name. 'Int' is the string name of the Int class.
Vadim, reasonably enough, wants a solution for both.
In the solution in this answer I simulate the two types of argument by randomly picking one and assigning it to $pkg-arg:
my $pkg-arg = (Int, 'Int').pick;
Now we need to normalize. If we've got a symbolic name we're good to go. But if it's a string name, we need to turn that into the symbolic name.
Vadim showed a couple ways to do this in the comments on their question. This solution uses a third option:
my \pkg-sym = $pkg-arg && ::($pkg-arg);
If $pkg-arg is a symbolic name, it'll be False. With a False LHS the && short-circuits and returns its LHS. If $pkg-arg is a string name, then the && will instead return its RHS, which is ::($pkg-arg) which is a symbol lookup using $pkg-arg as a string name.
The upshot is that pkg-sym ends up containing a package symbolic name (or a Failure if the lookup failed to find a matching symbolic name).
Which leaves the last line. That looks for a sub named $subname in the package pkg-sym:
my \sub-ref = &pkg-sym::($subname);
The & is needed to ensure the RHS is treated as a reference rather than as an attempt to call a routine. And pkg-sym has to be a sigilless identifier otherwise the code won't work.
At the end of these three lines of code sub-ref contains either a Failure or a reference to the wanted sub.
What is the Perl 6 way to tell the difference between an argument and no argument in a block with no explicit signature? I don't have any practical use for this, but I'm curious.
A block with no explicit signature puts the value into $_:
my &block := { put "The argument was $_" };
The signature is actually ;; $_? is raw. That's one optional argument. The #_ variable isn't defined in the block because there is no explicit signature.
There's the no argument, where $_ will be undefined:
&block(); # no argument
But there's also a one argument situation where $_ will be undefined. A type object is always undefined:
&block(Int);
But, an $_ with nothing in it is actually an Any (rather than, say, Nil). I can't tell the difference between these two cases:
&block();
&block(Any);
Here's a longer example:
my $block := {
say "\t.perl is {$_.perl}";
if $_ ~~ Nil {
put "\tArgument is Nil"
}
elsif ! .defined and $_.^name eq 'Any' {
put "\tArgument is an Any type object"
}
elsif $_ ~~ Any {
put "\tArgument is {$_.^name} type object"
}
else {
put "\tArgument is $_";
}
};
put "No argument: "; $block();
put "Empty argument: "; $block(Empty);
put "Nil argument: "; $block(Nil);
put "Any argument: "; $block(Any);
put "Int argument: "; $block(Int);
Notice the no argument and Any argument forms show the same things:
No argument:
.perl is Any
Argument is an Any type object
Empty argument:
.perl is Empty
Argument is Slip type object
Nil argument:
.perl is Nil
Argument is Nil
Any argument:
.perl is Any
Argument is an Any type object
Int argument:
.perl is Int
Argument is Int type object
As far as I know, the only way to know the number of parameters passed without an explicit signature, is to use #_ inside the body, which will generate a :(*#_) signature.
my &block := { say "Got #_.elems() parameter(s)" };
block; # Got 0 parameter(s)
block 42; # Got 1 parameter(s)
dd block.signature; # :(*#_)
Yeah, the good old #_ is still there, if you want it :-)
{ put $_.perl }
Is sort of similar to this: (which doesn't work)
-> ;; $_? is raw = CALLERS::<$_> { put $_.perl }
Since the default is default for $_ outside of the block is Any, if you don't place anything into $_ before you call the function you get Any.
To get something at all similar where you can tell the difference use a Capture :
my &foo = -> ;; |C ($_? is raw) {
unless C.elems {
# pretend it was defined like the first Block above
CALLER::<$_> := CALLER::CALLERS::<$_>
}
my $called-with-arguments := C.elems.Bool;
if $called-with-arguments {
say 'called with arguments';
} else {
say 'not called with arguments';
}
}
Here's how I solved this. I'd love to do this in a cleaner way but the cleverness of the language gets in the way and I have to work around it. This works for positional parameters but there are deeper shenanigans for named parameters and I won't deal with those here.
I had another question, Why does constraining a Perl 6 named parameter to a definite value make it a required value?, where the answers clarified that there are actually no optional parameters. There are merely parameters that have a default value and that there is an implicit default value if I don't explicitly assign one.
The crux of my problem is that I want to know when I gave the parameter a value and when I didn't. I give it a value through an argument or an explicit default. An implicit default is a type object of the right type. That's Any if I didn't specify a type. That implicit default must satisfy any constraint I specify.
The first goal is to tightly constrain the values a user can supply when they call code. If an undefined value is not valid then they shouldn't be allowed to specify one.
The second goal is to easily distinguish special cases in the code. I want to reduce the amount of special knowledge some part of the deeper code needs to know.
I can get the third case (where I know there was no argument or suitable default) by explicitly assigning a special value that I know can't be anything other meaningful thing. There's a value that's even more meaningless than Any. That's Mu. It's the most undefined values of all undefined values. The Any is one of two subtypes of Mu (the other is Junction) but you should almost never see a Mu end up in one of your values in normal code. Undefined things in user code start at Any.
I can create a constraint that checks for the type I want or for Mu and set a default of Mu. If I see a Mu I know there was no argument and that it's Mu because my constraint set that.
Since I'm using Mu there are some things I can't do, like use the === operator. Smart matching won't work because I don't want to test the inheritance chain. I can check the object name directly:
my $block := ->
$i where { $^a.^name eq 'Mu' or $^a ~~ Int:D } = Mu
{
say "\t.perl is {$i.perl}";
put do given $i {
when .^name eq 'Mu' { "\tThere was no argument" }
when Nil { "\tArgument is Nil" }
when (! .defined and .^name eq 'Any') {
"\tArgument is an Any type object"
}
when .defined {
"\tArgument is defined {.^name}"
}
default { "\tArgument is {.^name}" }
}
};
put "No argument: "; $block();
put "Empty argument: "; try $block(Empty); # fails
put "Nil argument: "; try $block(Nil); # fails
put "Any type argument: "; try $block(Any); # fails
put "Int type argument: "; try $block(Int); # fails
put "Int type argument: "; $block(5);
Now most of those invocations fail because they don't specify the right things.
If these were routines I could make multis for a small number of cases but that's an even worse solution in the end. If I had two parameters I'd need four multis. With three such parameters I'd need six. That's a lot of boilerplate code. But, blocks aren't routines so that's moot here.
While the Swift compiler (Xcode 7.2) seems perfectly correct in diagnosing an error for some source text equivalent to the following, it took long to detect the actual error made. Reason: the programmer needs to look not at the text marked, but elsewhere, thus mislead, wondering why an optional string and a non-optional string can not be operands of ??...
struct Outer {
var text : String
}
var opt : String?
var context : Outer
context = opt ?? "abc"
Obviously, the last line should have had context.text as the variable to be assigned. This is diagnosed:
confusion2.swift:9:19: error: binary operator '??' cannot be applied\
to operands of type 'String?' and 'String'
context = opt ?? "abc"
~~~ ^ ~~~~~
The message is formally correct. (I am assuming that type checking the left hand side establishes an expected type (Outer) for the right hand side, and this, then, renders the expression as not working, type-wise.) Taken literally, though, the diagnosis is wrong, as is seen when fixing the left hand side: ?? can be applied to operands of type String? and String.
Now, if this is as good as it gets, currently, in terms of compiler messages, what are good coping strategies? Is remembering
Type inference!
Context!
…
a start? Is there a more systematical approach? A check list?
Update (I'm adding to the list as answers come in. Thanks!)
break statements apart, so as to have several lines checked separately (#vacawama)
Beware of optionals (such as values got from dictionaries), see testSwitchOpt below
Another one
enum T {
case Str(String)
case Integer(Int)
}
func testSwitchOpt(x : T?) -> Int {
switch x {
case .Integer(let r): return r
default: return 0
}
}
The compiler says
optandswitch.swift:8:15: error: enum case 'Integer' not found in type 'T?'
case .Integer(let r): return r
A fix is to write switch x! (or a more cautious let), so as to make type checking address the proper type, I guess.
I could, perhaps should, file some report at Apple, but the issue seems to represent a recurring subject—I have seen this with other compilers—and I was hoping for some general and re-usable hints, if you don't mind sharing them.
Swift's type inference system is great in general, but it can lead to very confusing to outright wrong error messages.
When you get one of these Swift error messages that makes no sense, a good strategy is to break the line into parts. This will allow Swift to return a better error message before it goes too far down the wrong path.
For example, in your case, if you introduce a temporary variable, the real problem becomes clear:
// context = opt ?? "abc"
let temp = opt ?? "abc"
context = temp
Now the error message reads:
Cannot assign value of type 'String' to type 'Outer'
I'm learning Dart and see the following idiom a lot:
someFuture.then((_) => someFunc());
I have also seen code like:
someOtherFuture.then(() => someOtherFunc());
Is there a functional difference between these two examples?
A.k.a., What does passing _ as a parameter to a Dart function do?
This is particularly confusing given Dart's use of _ as a prefix for declaring private functions.
It's a variable named _ typically because you plan to not use it and throw it away. For example you can use the name x or foo instead.
The difference between (_) and () is simple in that one function takes an argument and the other doesn't.
DON’T use a leading underscore for identifiers that aren’t private.
Exception: An unused parameter can be named _, __, ___, etc. This
happens in things like callbacks where you are passed a value but you
don’t need to use it. Giving it a name that consists solely of
underscores is the idiomatic way to indicate the value isn’t used.
https://dart.dev/guides/language/effective-dart/style
An underscore (_) is usually an indication that you will not be using this parameter within the block. This is just a neat way to write code.
Let's say I've a method with two parameters useful and useless and I'm not using useless in the code block:
void method(int useful, int useless) {
print(useful);
}
Since useless variable won't be used, I should rather write the above code as:
void method(int useful, int _) { // 'useless' is replaced with '_'
print(useful);
}
From the Dart Doc - PREFER using _, __, etc. for unused callback parameters.
Sometimes the type signature of a callback function requires a
parameter, but the callback implementation doesn't use the
parameter. In this case, it's idiomatic to name the unused parameter
_. If the function has multiple unused parameters, use additional
underscores to avoid name collisions: __, ___, etc.
futureOfVoid.then((_) {
print('Operation complete.');
});
This guideline is only for functions that are both anonymous and
local. These functions are usually used immediately in a context
where it's clear what the unused parameter represents. In contrast,
top-level functions and method declarations don't have that context,
so their parameters must be named so that it's clear what each
parameter is for, even if it isn't used.
Copy paste the following code in DartPad and hit Run -
void main() {
Future.delayed(Duration(seconds: 1), () {
print("No argument Anonymous function");
});
funcReturnsInteger().then((_) {
print("Single argument Anonymous function " +
"stating not interested in using argument " +
"but can be accessed like this -> $_");
});
}
Future<int> funcReturnsInteger() async {
return 100;
}
That expression is similar to "callbacks" in node.js, the expression have relation to async task.
First remember that => expr expression is shorthand for {return *expr*}, now in someFuture.then((_) => someFunc()), someFuture is a variable of type Future, and this keeps your async task, with the .then method you tell what to do with your async task (once completed), and args in this method you put the callback ((response) => doSomethingWith(response)).
You learn more at Future-Based APIs and Functions in Dart. Thanks
Very common use, is when we need to push a new route with Navigator but the context variable in the builder is not going to be used:
// context is going to be used
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => NewPage(),
));
// context is NOT going to be used
Navigator.of(context).push(MaterialPageRoute(
builder: (_) => NewPage(),
));
I think what people are confusing here is that many think the _ in
someFuture.then((_) => someFunc());
is a parameter provided to the callback function which is wrong, its actually a parameter passed back from the function that you can give a name that you want (except reserved keywords of course), in this case its an underscore to show that the parameter will not be used. otherwise, you could do something like in example given above:((response) => doSomethingWith(response))
I've seen classes where constants are passed to methods, I guess its done to define some kind of setting in that function. I cant find it anywhere now to try to find out the logic, so I though I could ask here. How and why do you use this concept and where can I find more information about it?
The example below is written in PHP, but any language that handles constants would do I guess..
// Declaring class
class ExampleClass{
const EXAMPLE_CONST_1 = 0;
const EXAMPLE_CONST_2 = 1;
function example_method($constant(?)){
if($constant == ExampleClass::EXAMPLE_CONST_1)
// do this
else if($constant == ExampleClass::EXAMPLE_CONST_2)
// do that
}
}
// Using class
$inst = new ExampleClass();
$inst->example_method(ExampleClass::EXAMPLE_CONST_1);
To me its more clear to pass "ExampleClass::EXAMPLE_CONST_1" than to just pass "1", but it's that the only reason to pass constant?
Simply passing 1 doesn't say much. By having a constant you can have a description about the settings in the name.
example:
constant RAIN = 1;
method setWeather(RAIN);
Atleast that's how and why I use it.
It is always a good idea to avoid literals being passed around. By assigning a name, anyone reading your code has a chance to understand what that value means - a number has no meaning. It might also help you maintaining your code: If for some requirement the value has to be changed, you can easily do it in one place, instead of checking each and every value occurrence.