I would like this code:
[1,2,3].all? {|x| x.is_a?(Integer)}
to work using the &: method like:
[1,2,3].all?(&:is_a?(Integer))
but I get this error:
syntax error, unexpected '(', expecting ')'
I guess it's because I am calling is_a?(Integer) as a symbol.
How can I pass Integer to :is_a??
It is impossible. You cannot pass Integer (or anything else) to a symbol :is_a?. A symbol does not take an argument. No object in Ruby takes an argument (without a method call).
By the way, there is no such thing as &:.
You can get close to the notation you want with a lambda:
is_an_int = ->(o) { o.is_a?(Integer) }
[1,2,3].all?(&is_an_int)
or even closer, a lambda which returns a lambda:
is_a = ->(c) { ->(o) { o.is_a?(c) } }
[1,2,3].all?(&is_a[Integer])
Possibly more trouble than it is worth in this case but useful techniques none the less.
Related
In elixir is possible to use default arguments in function definitions, but I found it impossible to do so with single keyword list arguments like:
def do_stuff(
success: sucess \\ fn(conn) -> conn end,
error: error
) do
# ...
end
Also, I thought about avoiding this kind of "callback passing" style of coding by using something like JS promises but I couldn't find an implementation of promises for Elixir.
Maybe there's something built in right into the language that could help me write better code and closer abide to the elixir standards.
Main question: is possible to use default keyword arguments?
Side question: Is there something Elixir provides to help avoid this "callback passing" style of programming in favor of a more reactive/composable mechanism?
No, it's not possible to use default keyword arguments as keyword arguments are just syntactic sugar over a single keyword list:
do_stuff(success: ..., failure: ...)
is the same as
do_stuff([success: ..., failure: ...])
So a keyword list is really just a single argument. What you're doing in your function definition is matching on the keyword list passed to do_stuff/1: be sure to watch out for this as well, because your function definition will not match if the order of the keywords is not the same (i.e., do_stuff(failure: ..., success: ...)).
I think a nice way to overcome this is simply use two different arguments for the do_stuff function:
def do_stuff(success \\ fn(conn) -> conn end, failure \\ fn(err) -> err end)
This way default arguments work as expected. If you really need your argument to be a keyword list, then you can handle defaults inside the body of the function:
def do_stuff(options) do
success = options[:success] || (fn(conn) -> conn end)
failure = options[:failure] || (fn(err) -> err end)
end
Finally, about the "callback style" you mentioned, I don't know about anything that works much differently than just passing fn for when something is done, unless you start looking into concurrency and message passing.
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.
I have the following code:
update_using(&add_tabs_before_every_description_line, &add_tabs_before_every_photo_description_line, &add_links_to_photo_descriptions)
where the three arguments are lambda expressions declared as follows:
add_tabs_before_every_description_line = lambda do |mutable_viewable_gallery|
mutable_viewable_gallery.description = add_tabs_before_every_line(mutable_viewable_gallery.description, 2)
return mutable_viewable_gallery
end
It doesn't work in that I cannot pass a variable number of lambdas to update_using which is declared as follows:
def update_using(*args)
The error I'm getting is exactly about passing more than one lambda. It expects exactly one and then a closing bracket, not a comma. As soon as I remove the ampersands, the syntax error goes away, but then update_using it doesn't see it as lambdas.
generate_gallery.rb:50: syntax error, unexpected ',', expecting ')'
..._before_every_description_line, &add_tabs_before_every_photo...
...
I would like to be able to pass a variable number of lambdas to update_using. What am I doing wrong?
With & operator, you pass your lambda (or other proc, or object that could be converted to proc) to the method as block. Now, you can't pass any arguments after block param (so you also cannot pass more than one block to method). I guess you should pass your lambdas as 'regular' arguments, without &:
update_using(add_tabs_before_every_description_line, add_tabs_before_every_photo_description_line, add_links_to_photo_descriptions)
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'm writing a WxPerl program and instead of
$panel->SetDropTarget( MyTextDropTarget->new($panel) );
I wrote
$panel->SetDropTarget->( MyTextDropTarget->new($panel) );
and Perl didn't complain. (Perl called some function with some arguments, and the script did error out with an error message:
Usage: Wx::Window::SetDropTarget(THIS, target) at ./x.pl line 230.
I'm curious as to how Perl parsed the 'wrong' version.
Added edit:
Okay, so if $x = \&some_function, then I understand why
$x->($arg1, $arg2, ...)
calls some_function($arg1, $arg2, .....).
runrig's example is one possibility, but I'm quite sure that:
1) $panel contains a blessed object reference, not a string.
2) SetDropTarget is a method (in a base class) of $panel.
From the error message we can assume that SetDropTarget() being called. If runrig's example still applies here (and I'd guess it does), then even though SetDropTarget isn't followed by parentheses, i.e. I have
$panel->SetDropTarget->
instead of
$panel->SetDropTarget()->
Perl is still invoking SetDropTarget? (which inspects the number and type of its arguments and then fatally complains at runtime). Is that what happens?
Because it's perfectly valid syntax. $panel->SetDropTarget->( MyTextDropTarget->new($panel) ) means "Call the &SetDropTarget method from $panel, and then dereference the subref that &SetDropTarget returns." It's not what you meant to write, I'm guessing, but any error thrown would be at runtime, even in strict mode.
Your SetDropTarget likely does not return a code reference, but you can't tell that until runtime:
#!/usr/bin/perl
my $panel = 'main';
$panel->SetDropTarget->("bloomin'");
sub SetDropTarget {
return sub { print "Set the $_[0] drop target!\n" }
}
Perl parsed
$panel->SetDropTarget->( MyTextDropTarget->new($panel) );
to mean "$panel is an object; call its SetDropTarget method (optional parenthesis omitted), which will return a reference to a sub; call that sub, passing the the result of MyTextDropTarget->new($panel) as its single parameter."
That is, Perl expected SetDropTarget to be something like foo in the following code:
sub foo {
return sub {
my $bar = shift;
return $bar . ', world!';
}
}
foo()->('Hello');
foo->('Goodby');