Why flowjs doesn't throw error on empty array when array must be of a type? - flowtype

Can't understand why the following code pass flow check:
type Foo = "A" | "B" | "C"
const myFoo: Array<Foo> = []
Isn't Array<Foo> enforcing the array to have some Foo type?
I'm a bit confused.
Flow repl: https://flow.org/try/#0C4TwDgpgBAYg9nKBeKAiAgqqAfNAhLXVAYVQCgyBjOAOwGdgoBbEeOALinQCduBDEAB42APmRQA2gF0yQA

The type Array<Foo> means that all elements in the array must have type Foo. This is true for the empty array []: all elements in this array have type Foo. It just so happens that there are no elements in the array. Flow will enforce that all elements added to the array will be of type Foo.

Related

why do I need parenthesis in this dictionary initializer, in F#

with these types:
type A =
| AA
| AB
type B =
Dictionary<int, int>()
I initialize a dictionary:
Dictionary<A, B>(dict [ (A.AA, B()); (A.AB, B()) ])
but I do not understand why I need to put parenthesis after B, in the initialization code.
the following:
Dictionary<A, B>(dict [ (A.AA, B); (A.AB, B) ])
will not compile. I understand that 'B' may represent the type and 'B()' an instance of it, but I don't understand why the '()' would represent an instance?
As an additional question:
type B =
Dictionary<int, int>()
and
type B =
Dictionary<int, int>
both seem to work. Is any of the two preferred, and, if so, why?
First of all, the declaration type B = Dictionary<int, int>() does not work for me. I get an error "Unexpected symbol '(' in member definition", exactly as I would expect. Are you sure it's working for you? Which version of F# are you using?
The type Dictionary<_,_> is a class. Classes are not the same as discriminated unions (which the type A is). They are a different sort of type.
In particular, to create a value of a class type, one needs to call a constructor and pass it some parameters. This is exactly what you're doing in your very own code:
Dictionary<A, B> (dict [ (A.AA, B()); (A.AB, B()) ])
^--------------^ ^---------------------------------^
| |
constructor |
|
parameter passed to the constructor
Some classes have multiple constructors. Dictionary is one of such types.
Some constructors have no parameters, but you still have to call them. This is what you do with empty parens.
F# models parameterless .NET methods and constructors as functions that have a single parameter, and that parameter is of type unit. This is what you're doing when you say B()
B ()
^ ^^
| |
| single parameter of type unit
|
constructor
If you just say B without a parameter, then what you get is a function of type unit -> B - that is a function that expects a single parameter of type unit and when you pass it such parameter, it would return you a value of type B.

Why function receive extra argument

When I run an function with the code below:
elements = ["A", "B"]
for element <- elements, into: [] do
struct(element, [])
end
Elixir raise this exception:
** (FunctionClauseError) no function clause matching in Kernel.struct/3
The following arguments were given to Kernel.struct/3:
# 1
"A"
# 2
[]
# 3
#Function<18.114860832/2 in Kernel.struct/2>
Attempted function clauses (showing 4 out of 4):
defp struct(struct, [], _fun) when is_atom(struct)
defp struct(struct, fields, fun) when is_atom(struct)
defp struct(%_{} = struct, [], _fun)
defp struct(%_{} = struct, fields, fun)
Why Elixir pass an function as third parameter to Kernel.struct function?
The reason you are seeing Kernel.struct/3 is that Kernel.struct/2 calls a private Kernel.struct/3 clause internally.
The reason for the error, that there is no matching function clause, is because the first argument "A" is not a struct or an atom. Please read the documentation for struct/2:
The struct argument may be an atom (which defines defstruct) or a struct itself.
You are passing a string, which is not a valid argument.

Flow: shape types and additional optional fields

I often find myself needing to do the following, and Flow makes it stupidly difficult:
/* #flow */
type Foo = {
+foo?: number,
}
type FooBar = {
+foo?: number,
+bar?: number,
}
const foo: Foo = {foo: 2}
function process(arg: $ReadOnly<FooBar>) {
}
process(foo)
Is there any good way to do this? I get the following error:
17: process(foo)
^ Cannot call `process` with `foo` bound to `arg` because property `bar` is missing in `Foo` [1] but exists in `FooBar` [2].
References:
12: const foo: Foo = {foo: 2}
^ [1]
14: function process(arg: $ReadOnly<FooBar>) {
^ [2]
Flow defaults to object types being inexact; this means that, although Foo is only declared to explicitly have a single (optional) property foo of type number, a variable of type Foo could theoretically have additional properties. For example, a variable of type Foo could have a property bar. And, since bar is not typed in Foo, bar's type is unrestricted (i.e., not necessarily number). As a result, if you were to interact with arg.bar in process and Flow allowed arg to be of type Foo, you are not guaranteed to be interacting with a number. Thus, Flow complains.
One way to fix this is to use exact object types. If Flow knows that a variable of type Foo will never have a bar property, then it can safely be passed into process. So, you could type Foo as:
type Foo = {|
+foo?: number,
|};
Try Flow
(Note: the $ReadOnly utility type is not necessary with the above definition of Foo and the original definition of FooBar because bar is not writable. Though, certainly, it's fine to keep $ReadOnly.)

Flowtype: array of possible strings cannot be empty?

if I create this Flow type:
export type List = [
'some' |
'strings' |
'allowed' |
'to' |
'use'
];
I am not allowed to:
const myList: List = [];
this is the error:
empty array literal:
This type is incompatible with a tuple type that expects a 1st element of non-optional type string enum
The only thing I can come up with is adding typeof undefined to the possible values list. But there must be a simpeler way to allow it to be empty?
You defined a tuple of one element, you may want
type Element =
'some' |
'strings' |
'allowed' |
'to' |
'use';
export type List = Element[];
// or export type List = Array<Element>;
const myList: List = []

How to get the value of field

In julia i can get a list of fields like so
INPUT:
type Foobar
foo::Int
bar::String
end
baz = Foobar(5,"GoodDay")
fieldnames(baz)
OUTPUT:
2-element Array{Symbol,1}:
:foo
:bar
But how can access the values of those fields, given the names that I am finding dynamically?
I know one way is to build the expression myself:
fieldvalue(v,fn::Symbol) = eval(Expr(:(.), v, QuoteNode(fn)))
That is kinda scary looking, so I think there is a better way.
Usecase:
INPUT:
function print_structure(v)
for fn in fieldnames(v)
println(fn,"\t", fieldvalue(v,fn))
end
end
print_structure(baz)
OUTPUT:
foo 5
bar GoodDay
getfield(baz, :foo) will get the field foo from variable baz i.e. the result will be the same as baz.foo.
Note :foo has to be a symbol, therefore if you somehow get the field name in a string, it should be used as follows: getfield(varname, Symbol(fieldnamestring))
You can also use e.g. getfield(baz, 2) to get the 2nd field without needing to know its name.

Resources