We need an option that would wrap the trailing curly brace of the initializer to a new line, in case of multiple parameters:
SomeStruct a{
.i = 1,
.f = 2.2};
vs
SomeStruct a{
.i = 1,
.f = 2.2
};
In this case, the initializer with one parameter remains on the same line:
SomeStruct a{.i = 1};
Related
I'm calling a C# API which uses overloads and optional parameters.
Unfortunately, one of the overloads is a params object[] and F# selects it over a more specific overload which I intend to call. How do I make F# select the overload I want?
Here's a small repro. And here is a link to the actual API.
open System
open System.Linq.Expressions
type S =
static member Foo(expression: Expression<Func<int>>, ?gg: string) =
"expression"
static member Foo([<ParamArray>] args: obj[]) =
"params array"
[<EntryPoint>]
let main argv =
// This prints "params array", but I want it to print "expression"
let result = S.Foo(fun () -> 3, "")
printfn "%s" result
0
To call the expression version with two arguments, you need:
let result = S.Foo((fun () -> 3), "")
In your code, you've actually defined a function that returns a (3, "") tuple, which is only a single argument.
I've read the-f-equivalent-of-cs-out but still I can't make it work for my case (the simplest solution/syntax).
I have this method in a C# project:
//<Project Sdk="Microsoft.NET.Sdk">
//<TargetFrameworks>netcoreapp3.1;netstandard2.0</TargetFrameworks>
public static void ABC(out byte[] a, out byte[] b, byte[] c)
{
var aaa = new byte[10];
var bbb = new byte[10];
a = aaa;
b = bbb;
}
Now, I want to use it in a F# project:
I'm using FSharp.Core 4.7.2
(* <Project Sdk="Microsoft.NET.Sdk">
<TargetFrameworks>netcoreapp3.1;netstandard2.0</TargetFrameworks> *)
let a,b = ABC(c)
I'm imitating the syntax of TryParse and this compiles without errors:
let success, number = System.Int32.TryParse("0")
The compiler on my ABC(c) call complains about the fact the signature asks for 3 parameters, not 1.
Compared to the TryParse I see 2 differences:
It does not return void
It uses Array objects
The compiler accepts this syntax:
let a = Array.empty<byte>
let b = Array.empty<byte>
ABC(ref a, ref b, c)
but:
I think it is not correct to use ref here, not in this way (because a and b are not mutable)
I'd like to use the clean syntax similar to TryParse and I WANT to know why it does not work here
I can change the C# project code, but replacing all the out parameters in that proejct will be a second step and maybe a new qeustion if I have difficulties or doubt.
[Update: parameter position]
I played a little with this and seems like I found when the "simple" syntax (without passing ref parameters) is broken.
public static void TryParseArray(string input, out int[] result) {
result = new int[0];
}
public static void TryParseArray_2(out int[] result, string input) {
result = new int[0];
}
let arr = csharp.TryParseArray("a") // OK
let arr = csharp.TryParseArray_2("a") // ERROR
It seems like the out parameter must be at the end (= not followed by normal parameters) in the C# methods, to make possible for F# to use them as returned tuple.
You correctly noticed that the "simplified" F# syntax for turning out parameters into returned tuples only works in very limited situations - only when you have one parameter and it is the last one. In other words, this feature helps with some common patterns, but it does not fully replace out parameters.
If you want to use out parameter in F#, you can either pass a reference to a local mutable variable using the &var syntax, or you can specify a reference cell of type int ref as an argument. The following shows the two options using the standard TryParse method:
// Using a local mutable variable
let mutable n = 0
Int32.TryParse("42", &n)
printfn "Got: %d" n
// Using a reference cell initialized to 0
let n = ref 0
Int32.TryParse("42", n)
printfn "Got: %d" n.Value
Hm, well that was a hard question to name appropriately. Anyway, I'm wondering why, given this type declaration
type T = {
C : int
}
This does not compile:
let foo () =
{
C = printfn ""; 3
}
but this does:
let foo () =
{
C =
printfn ""; 3
}
Compiler bug or by design?
"Works as designed" probably more than a "bug", but it's just an overall weird thing to do.
Semicolon is an expression sequencing operator (as in your intended usage), but also a record field separator. In the first case, the parser assumes the latter, and gets confused by it. In the second case, by indenting it you make it clear that the semicolon means expression sequencing.
You could get away with this without splitting the field over two lines:
let foo () =
{
C = (printfn ""; 3)
}
This code:
function foo()
return 1, 2, 3
end
bar = {}
bar = {a, b, c = foo()}
produces:
bar.a = nil
bar.b = nil
bar.c = 1
How can this be written so that you get:
bar.a = 1
bar.b = 2
bar.c = 3
without having to write something like this:
function foo()
return 1, 2, 3
end
bar = {}
a, b, c = foo()
bar = {a = a, b = b, c = c}
BLUF
There's no straight forward or elegant way to do this. You'll have to do it manually like this
local r = { f() } --> store all returned values in r
local bar = { }
local c = string.byte 'a' --> start with 'a'
for _, v in ipairs(r) do
local t = string.char(c)
bar[t] = v --> assign each value to respective letter
c = c + 1
end
If you'd had a, b, c = foo() you'd get all the three values assigned to the three variables. However, you've
bar = { a, b, c = foo() }
This table constructor expression will get interpreted as the keys a, b, c getting inserted into the table, with only the last key having an associated value (aside: keys with no associated value are taken as nil; hence a and b never get inserted). Since there's only one variable to take the values returned by foo, except the first everything else it returns are discarded.
Alternatively bar = { foo() } will assign all values returned by foo as array values of bar. However, the key to access these would [1], [2], etc. and not 'a', 'b', etc.
Read below to know when the returned values get discarded and when they don't.
TL;DR
All returned values are retained only when the function call is the last/only expression in a list of expressions; elsewhere all except the first are discarded.
Function call as a statement
In Lua, when we return multiple results from a function, all of them get discarded if the function call is a statement by itself.
foo()
will discard all three return values.
Function call in an expression
If it's used in an expression, only the first will be retained and everything else will be discarded.
x = foo() - 1
print(x) -- prints 0; the values 2, 3 are discarded
Function call in an expression list
The entire list of values returned is retained only when the call appears as the last/only item in a list of expressions. Such list of expressions occur at four places in Lua:
Multiple assignment
E.g. local a, b, c, d = 0, f(). Here b, c, d get the values 1, 2, 3 respectively.
Table constructor
E.g. local t = { 0, f() }. All values returned by f are put into t following the first 0.
Function call arguments
E.g. g(a, f()). g would receive 4, not 2, arguments. a and the three values from f.
return statement
E.g. return 'a', f(). Additional to the string 'a', all values returned by f will be received at the calling end.
In all these situations, had f appeared not as the last expression in the list or wasn't the only expression, then all values it returned except the first would've been discarded.
Multiple assignment statement
In the multiple assignment statement, when the number of values assigned is lesser than number of variables, the extra variables be assigned to nil. When it's the other way around i.e if the number of variables are lesser, the extra values are discarded.
a, b, c = 1, 2 -- a = 1, b = 2, c = nil
a, b, c = 1, 2, 3, 4 -- 4 gets discarded
bar = {}
bar.a, bar.b, bar.c = foo()
bar = {}
local abc = foo()
bar.a, bar.b, bar.c = abc, abc, abc
Simply bar.a, bar.b, bar.c = foo() will only set bar.a to foo(), the other two will be set to nil because they get set to the second and third values respectively, and you've only given one value.
If you can, have foo() return a table formatted the right way.
function foo()
return {a = 1, b = 2, c = 3}
end
bar = foo()
Consider the following piece of code:
class Person {
String id;
String name;
ConnectionFactory connectionFactory;
// What is this constructor doing?
Person({this.connectionFactory: _newDBConnection});
}
If you precede a constructor's argument with this, the corresponding field will be automatically initialized, but why {...}?
This makes the argument a named optional argument.
When you instantiate a Person you can
Person p;
p = new Person(); // default is _newDbConnection
p = new Person(connectionFactory: aConnectionFactoryInstance);
without {} the argument would be mandatory
with [] the argument would be an optional positional argument
// Constructor with positional optional argument
Person([this.connectionFactory = _newDBconnection]);
...
Person p;
p = new Person(); // same as above
p = new Person(aConnectionFactoryInstance); // you don't specify the parameter name
Named optional parameters are very convenient for boolean arguments (but of course for other cases too).
p = new Person(isAlive: true, isAdult: false, hasCar: false);
There is a specific order in which these argument types can be used:
mandatory (positional) arguments (only positional arguments can be mandatory)
optional positional arguments
(optional) named arguments (named arguments are always optional)
Note that positional and named optional arguments use a different delimiter for the default value.
The named requires : but the positional requires =. The language designers argue that the colon fits better with the Map literal syntax (I would at least have used the same delimiter for both).
= is supported as delimiter since Dart 2 and preferred according to the style guide while : is still supporzed.
See also:
What is the difference between named and optional parameters in Dart?
Functions Are Fun, Pt 1 - Dart Tips, Ep 6
Chapter 2. A Tour of the Dart Language - Functions
Chapter 2. A Tour of the Dart Language - Constructors
Dart functions allow positional parameters, named parameters, and optional positional and named parameters, or a combination of all of them.
Positional parameters are simply without decoration:
void debugger(String message, int lineNum) {
// ...
}
Named parameters means that when you call a function, you attach the argument to a label. This example calls a function with two named parameters:
debugger(message: 'A bug!', lineNum: 44);
Named parameters are written a bit differently. You wrap any named parameters in curly braces ({ }). This line defines a function with named parameters:
void debugger({String message, int lineNum}) {
Named parameters, by default, are optional. But you can annotate them and make them required:
Widget build({#required Widget child}) {
//...
}
Finally, you can pass positional parameters that are optional, using [ ]:
int addSomeNums(int x, int y, [int z]) {
int sum = x + y;
if (z != null) {
sum += z;
}
return sum;
}
You call that function like this:
addSomeNums(5, 4)
addSomeNums(5, 4, 3)
You can define default values for parameters with the = operator in the function signature, and the function can be simplified as below:
addSomeNums(int x, int y, [int z = 5]) => x + y + z;
the this. connectionFactory in
Person({this.connectionFactory: _newDBConnection});
is called Automatic Class Member Variable Initialization. See this example