Dart supports both named optional parameters and positional optional parameters. What are the differences between the two?
Also, how can you tell if an optional parameter was actually specified?
Dart has two types of optional parameters: named and positional. Before I discuss the differences, let me first discuss the similarities.
Dart's optional parameters are optional in that the caller isn't required to specify a value for the parameter when calling the function.
Optional parameters can only be declared after any required parameters.
Optional parameters can have a default value, which is used when a caller does not specify a value.
Positional optional parameters
A parameter wrapped by [ ] is a positional optional parameter. Here is an example:
getHttpUrl(String server, String path, [int port=80]) {
// ...
}
In the above code, port is optional and has a default value of 80.
You can call getHttpUrl with or without the third parameter.
getHttpUrl('example.com', '/index.html', 8080); // port == 8080
getHttpUrl('example.com', '/index.html'); // port == 80
You can specify multiple positional parameters for a function:
getHttpUrl(String server, String path, [int port=80, int numRetries=3]) {
// ...
}
The optional parameters are positional in that you can't omit port if you want to specify numRetries.
getHttpUrl('example.com', '/index.html');
getHttpUrl('example.com', '/index.html', 8080);
getHttpUrl('example.com', '/index.html', 8080, 5);
Of course, unless you know what 8080 and 5 are, it's hard to tell what those apparently magic numbers are. You can use named optional parameters to create more readable APIs.
Named optional parameters
A parameter wrapped by { } is a named optional parameter. Here is an example:
getHttpUrl(String server, String path, {int port = 80}) {
// ...
}
You can call getHttpUrl with or without the third parameter. You must use the parameter name when calling the function.
getHttpUrl('example.com', '/index.html', port: 8080); // port == 8080
getHttpUrl('example.com', '/index.html'); // port == 80
You can specify multiple named parameters for a function:
getHttpUrl(String server, String path, {int port = 80, int numRetries = 3}) {
// ...
}
Because named parameters are referenced by name, they can be used in an order different from their declaration.
getHttpUrl('example.com', '/index.html');
getHttpUrl('example.com', '/index.html', port: 8080);
getHttpUrl('example.com', '/index.html', port: 8080, numRetries: 5);
getHttpUrl('example.com', '/index.html', numRetries: 5, port: 8080);
getHttpUrl('example.com', '/index.html', numRetries: 5);
I believe named parameters make for easier-to-understand call sites, especially when there are boolean flags or out-of-context numbers.
Checking if optional parameter was provided
Unfortunately, you cannot distinguish between the cases "an optional parameter was not provided" and "an optional parameter was provided with the default value".
Note: You may use positional optional parameters or named optional parameters, but not both in the same function or method. The following is not allowed.
thisFunctionWontWork(String foo, [String positonal], {String named}) {
// will not work!
}
In Dart with my understanding, method parameter can be given in two type.
Required parameter
Optional parameter (positional, named & default)
>> Required Parameter
Required parameter is a well know old style parameter which we all familiar with it
example:
findVolume(int length, int breath, int height) {
print('length = $length, breath = $breath, height = $height');
}
findVolume(10,20,30);
output:
length = 10, breath = 20, height = 30
>> Optional Positional Parameter
parameter will be disclosed with square bracket [ ] & square bracketed parameter are optional.
example:
findVolume(int length, int breath, [int height]) {
print('length = $length, breath = $breath, height = $height');
}
findVolume(10,20,30);//valid
findVolume(10,20);//also valid
output:
length = 10, breath = 20, height = 30
length = 10, breath = 20, height = null // no value passed so height is null
>> Optional Named Parameter
parameter will be disclosed with curly bracket { }
curly bracketed parameter are optional.
have to use parameter name to assign a value which separated with colan :
in curly bracketed parameter order does not matter
these type parameter help us to avoid confusion while passing value for a function which has many parameter.
example:
findVolume(int length, int breath, {int height}) {
print('length = $length, breath = $breath, height = $height');
}
findVolume(10,20,height:30);//valid & we can see the parameter name is mentioned here.
findVolume(10,20);//also valid
output:
length = 10, breath = 20, height = 30
length = 10, breath = 20, height = null
>> Optional Default Parameter
same like optional named parameter in addition we can assign default value for this parameter.
which means no value is passed this default value will be taken.
example:
findVolume(int length, int breath, {int height=10}) {
print('length = $length, breath = $breath, height = $height');
}
findVolume(10,20,height:30);//valid
findVolume(10,20);//valid
output:
length = 10, breath = 20, height = 30
length = 10, breath = 20, height = 10 // default value 10 is taken
thanks for the clear explanation given from this video link, credits to the video creator.
video link : OptionalPositionalParameters
video link : OptionalNamedParameters
video link : OptionalDefaultParameters
When the parameter of a function is specified using "paramName : value" syntax, then it is a named parameter. Such parameters can be rendered optional by enclosing them between [ and ] brackets. A rudimentary demonstration of this function can be demonstrated in the following Hello World program:
sayHello([String name = ' World!']) {
print('Hello, ${name}');
}
void main() {
sayHello('Govind');
}
Positional Parameters:
They are same as default parameters. For example:
void add(int x, [int y = 3]);
Here y has the default value of 3
Named Parameters:
These are parameters that can be passed in any order by passing the name of the parameter followed by the passed value. For example:
void sum({int num1, int num2});
This function is called like this:
sum(num1: 12, num2: 24);
Also named parameters can also have default values.
Examples from Flutter
Named arguments
The Duration class constructor takes named parameters:
const Duration(
{int days = 0,
int hours = 0,
int minutes = 0,
int seconds = 0,
int milliseconds = 0,
int microseconds = 0}
)
Positional arguments
The DateTime class's constructor has 1 required positional argument, and 7 optional positional arguments:
DateTime(
int year,
[int month = 1,
int day = 1,
int hour = 0,
int minute = 0,
int second = 0,
int millisecond = 0,
int microsecond = 0]
)
When to use which?
For dates/ times, it doesn't make sense to specify a day if you don't specify a month. If I told you Monday, you wouldn't know which Monday I was talking about. It doesn't make sense if you specify a month but don't specify a year. Dates naturally go from coarse to fine. Of course, in reality you would assume which Monday would be next monday, but programs can't assume this.
For Duration, it doesn't matter which you specify. A Duration of time can be 1 second, or 1 millisecond, or 5 days. If I told you wait 5 seconds, I don't need to tell you 0 days, 0 hours, 0 minutes and 5 seconds.
From doc we get that both positional and named parameters are optional, which means they all can be absent.
In my opinion, named parameters are more strict than positional ones. For example, if you declare such a method:
String say({String from, String msg})
Above from and msg are named parameters, when you call method say you must use say(from: "xx", msg: "xx"). The keys cannot be absent.
However if you use positional parameters, you are free.
In the below method:
getBMI(float weight, float height, {int age = 80}) {
// method body
}
weight and height are positional parameters, and age is named parameter.
We will call the method like below:
getBMI(65, 175, age: 35);
As you can see maned parameters make for easier-to-understand call sites.
Related
Using svelte motion I need to create an array of springs for various objects.
import { spring, type Spring } from 'svelte/motion';
.
.
.
let coords: Array<Spring<{ x: number; y: number }>> = [];
for (let i = 0; i < foo.length; i++) {
coords.push(
spring(
{ x: 50, y: 0 },
{
stiffness: 0.1,
damping: 0.1
}
)
);
}
Now when I use it in inline style
<img alt="eggs" src="./spam"
style="transform: translate({$coords[j].x}px,{$coords[j].y}px)"
/>
I get the following error-
'coords' is not a store with a 'subscribe' method
Error: 'coords' is not a store with a 'subscribe' method
No overload matches this call.
Overload 1 of 2, '(store:SvelteStore<any>):any' gave the following error.
Argument of type 'Spring<{x:number; y:number;}>[]' is not assignable to the parameter of type 'SvelteStore<any>'.
Property 'subscribe' is missing in type 'Spring<{x:number; y:number;}>[]' but is required in type 'SvelteStore<any>'.
Overload 2 of 2, '(store:SvelteStore<any> | null |undefined ):any' gave the following error.
Argument of type 'Spring<{x:number; y:number;}>[]' is not assignable to the parameter of type 'SvelteStore<any>'.
How do I solve this without creating a custom store.
A $storeVar variable will only work for a store declared in a top-level variable. If you only need access to one of those stores, you could have a line like this in your <script>:
$: myCoords = coords[j];
and then $myCoords.x and $myCoords.y will work as you'd expect.
If you need to subscribe to every store in an array, you'll need to manage the subscriptions yourself. It's not hard, but you'll need to ensure every subscription gets unsubscribed at the appropriate time.
import { onDestroy } from "svelte";
let storeValues = [];
for ( let [i, store] of coords.entries() ) {
let unsubscribe = store.subscribe( (value) => {
storeValues[i] = value; // Svelte makes this reactive
} );
onDestroy( unsubscribe );
}
I am learning Dart, and I can't understand the logic behind this code if anyone can help:
Function applyMultiplier(num multiplier) {
return (num value) {
return value * multiplier;
};
}
final triple = applyMultiplier(3);
print(triple(6)); //output 18
There is an anonymous function inside a named function.
We assigned a function to a variable.
What I don't understand is how did we pass from triple to value. I can't understand the logic behind.
Well, the function applyMultiplier takes a num as argument and returns a function that itself returns the value it is given multiplied by another multiplier. final tripple = applyMultiplier(3) stores this function that is returned from applyMultiplier in the variable triple. Because the variable triple then stores a function it can also be used like a function.
Functions in Dart are first-class objects, allowing you to pass them to other objects or functions.
void main() {
var shout = (msg) => ' ${msg.toUpperCase()} ';
print(shout("yo"));
}
This made me wonder if there was a way to modify a function a run time, just like an object, prior to passing it to something else. For example:
Function add(int input) {
return add + 2;
}
If I wanted to make the function a generic addition function, then I would do:
Function add(int input, int increment) {
return add + increment;
}
But then the problem would be that the object I am passing the function to would need to specify the increment. I would like to pass the add function to another object, with the increment specified at run time, and declared within the function body so that the increment cannot be changed by the recipient of the function object.
The answer seems to be to use a lexical closure.
From here: https://dart.dev/guides/language/language-tour#built-in-types
A closure is a function object that has access to variables in its
lexical scope, even when the function is used outside of its original
scope.
Functions can close over variables defined in surrounding scopes. In
the following example, makeAdder() captures the variable addBy.
Wherever the returned function goes, it remembers addBy.
/// Returns a function that adds [addBy] to the
/// function's argument.
Function makeAdder(int addBy) {
return (int i) => addBy + i;
}
void main() {
// Create a function that adds 2.
var add2 = makeAdder(2);
// Create a function that adds 4.
var add4 = makeAdder(4);
assert(add2(3) == 5);
assert(add4(3) == 7);
}
In the above cases, we pass 2 or 4 into the makeAdder function. The makeAdder function uses the parameter to create and return a function object that can be passed to other objects.
You most likely don't need to modify a closure, just the ability to create customized closures.
The latter is simple:
int Function(int) makeAdder(int increment) => (int value) => value + increment;
...
foo(makeAdder(1)); // Adds 1.
foo(makeAdder(4)); // Adds 2.
You can't change which variables a closure is referencing, but you can change their values ... if you an access the variable. For local variables, that's actually hard.
Mutating state which makes an existing closure change behavior can sometimes be appropriate, but those functions should be very precise about how they change and where they are being used. For a function like add which is used for its behavior, changing the behavior is rarely a good idea. It's better to replace the closure in the specific places that need to change behavior, and not risk changing the behavior in other places which happen to depend on the same closure. Otherwise it becomes very important to control where the closure actually flows.
If you still want to change the behavior of an existing global, you need to change a variable that it depends on.
Globals are easy:
int increment = 1;
int globalAdder(int value) => value + increment;
...
foo(globalAdd); // Adds 1.
increment = 2;
foo(globalAdd); // Adds 2.
I really can't recommend mutating global variables. It scales rather badly. You have no control over anything.
Another option is to use an instance variable to hold the modifiable value.
class MakeAdder {
int increment = 1;
int instanceAdd(int value) => value + increment;
}
...
var makeAdder = MakeAdder();
var adder = makeAdder.instanceAdd;
...
foo(adder); // Adds 1.
makeAdder.increment = 2;
foo(adder); // Adds 2.
That gives you much more control over who can access the increment variable. You can create multiple independent mutaable adders without them stepping on each other's toes.
To modify a local variable, you need someone to give you access to it, from inside the function where the variable is visible.
int Function(int) makeAdder(void Function(void Function(int)) setIncrementCallback) {
var increment = 1;
setIncrementCallback((v) {
increment = v;
});
return (value) => value + increment;
}
...
void Function(int) setIncrement;
int Function(int) localAdd = makeAdder((inc) { setIncrement = inc; });
...
foo(localAdd); // Adds 1.
setIncrement(2);
foo(localAdd); // Adds 2.
This is one way of passing back a way to modify the local increment variable.
It's almost always far too complicated an approach for what it gives you, I'd go with the instance variable instead.
Often, the instance variable will actually represent something in your model, some state which can meaningfully change, and then it becomes predictable and understandable when and how the state of the entire model changes, including the functions referring to that model.
Using partial function application
You can use a partial function application to bind arguments to functions.
If you have something like:
int add(int input, int increment) => input + increment;
and want to pass it to another function that expects to supply fewer arguments:
int foo(int Function(int input) applyIncrement) => applyIncrement(10);
then you could do:
foo((input) => add(input, 2); // `increment` is fixed to 2
foo((input) => add(input, 4); // `increment` is fixed to 4
Using callable objects
Another approach would be to make a callable object:
class Adder {
int increment = 0;
int call(int input) => input + increment;
}
which could be used with the same foo function above:
var adder = Adder()..increment = 2;
print(foo(adder)); // Prints: 12
adder.increment = 4;
print(foo(adder)); // Prints: 14
i'm developing an app related to social messanging and i want to convert big numbers to Human readable format (e.g. 1500 to 1.5k) and also i'm new to Dart.
Your help will be appreciated.
You can use the NumberFormat class of flutter which has some in built functions for results you want..
Check out this link for NumberFormat class of flutter
Example:
This is one way if you want to use currency..
var _formattedNumber = NumberFormat.compactCurrency(
decimalDigits: 2,
symbol: '', // if you want to add currency symbol then pass that in this else leave it empty.
).format(numberToFormat);
print('Formatted Number is: $_formattedNumber');
Example:
This example is with locale.
var _formattedNumber = NumberFormat.compactCurrency(
decimalDigits: 2,
locale: 'en_IN'
symbol: '',
).format(numberToFormat);
print('Formatted Number is: $_formattedNumber');
The output of this is code would be:
If 1000 is entered then 1K is the output
Another way is by just using NumberFormat.compact() which gives the desired output...
// In this you won't have to worry about the symbol of the currency.
var _formattedNumber = NumberFormat.compact().format(numberToFormat);
print('Formatted Number is: $_formattedNumber');
The output of above example will also be:
If 1000 is entered then 1K is the output
I tried this and is working...
Make a class and used its static method every where.
class NumberFormatter{
static String formatter(String currentBalance) {
try{
// suffix = {' ', 'k', 'M', 'B', 'T', 'P', 'E'};
double value = double.parse(currentBalance);
if(value < 1000000){ // less than a million
return value.toStringAsFixed(2);
}else if(value >= 1000000 && value < (1000000*10*100)){ // less than 100 million
double result = value/1000000;
return result.toStringAsFixed(2)+"M";
}else if(value >= (1000000*10*100) && value < (1000000*10*100*100)){ // less than 100 billion
double result = value/(1000000*10*100);
return result.toStringAsFixed(2)+"B";
}else if(value >= (1000000*10*100*100) && value < (1000000*10*100*100*100)){ // less than 100 trillion
double result = value/(1000000*10*100*100);
return result.toStringAsFixed(2)+"T";
}
}catch(e){
print(e);
}
}
}
In my custom dissector, I have 32 bit signed gint32 value in datagram, whose header field is described as
&hf_TargetPosition,
{ "Target Position", "machine.RxPdo",
FT_INT32, BASE_DEC, NULL, 0xffffffff,
NULL, HFILL }
Before adding this item to proto_tree, I need to scale it with double value.
Since there is no tvb_get* function that return signed gint32, I used tvb_get_letohl function to get 32 bit signed value
gint32 stmp32 = (gint32)tvb_get_letohl(tvb, suboffset);
gdouble tpos = (gdouble)stmp32 * 0.000001;
How can I add tpos to proto_tree ?
As a workaround I tried not to cast tpos to double and use proto_tree_add_int_format_value function
gint32 tpos = stmp/1000000;
proto_tree_add_int_format_value(Dout_tree, hf_TargetPosition, tvb, suboffset, 4, tpos, "%lf");
But could not get desired signed decimal-point/float value in displayed tree.
I need it to be raw integral value and display it as fractional unit.
Then you want
gint32 stmp32;
...
stmp32 = (gint32)tvb_get_letohl(tvb, suboffset);
proto_tree_add_int_format_value(Dout_tree, hf_TargetPosition, tvb, suboffset, 4, stmp32, "%lf", stmp32/1000000.0);