Error: The operator '+' isn't defined for the class 'Object' - dictionary

As a complete Dart beginner coming from python and javascript, I find this behavior quite strange:
var user = {'name': 'John Doe', 'birth_y': 1980};
2021-user['birth_y'] // is 41
But if the operator is on the right.
user['birth_y'] + 41 // error
The error:
Error: The operator '+' isn't defined for the class 'Object'.
- 'Object' is from 'dart:core'.
Try correcting the operator to an existing operator, or defining a '+' operator.
user['birth_y'] + 41;
^
From the error, one guesses that for maps with mixed types, entries have type 'Object', Yet:
user['birth_y'] is int // true
user['birth_y'].runtimeType // int
This behavior is also exhibited by lists of mixed types,
What am I missing?

Dart does a statically analysis of your program before running it. In this analyze phase, it will look at the data type of your variables and see if it is statically safe.
In your case you have this Map:
var user = {'name': 'John Doe', 'birth_y': 1980};
Since your Map contains different types of values, Dart will try to see which data type can be used for all your values. In this case, the only thing String and int shares is the Object type. So user is being analyzed to be of the type Map<String, Object>.
This means that when you get a object from user, the only thing the analyzer can be sure about is it is of the type Object.
So when you do:
user['birth_y'] + 41
The analyzer will assume you get a Object which does not have the + operator.
You should in general not use Map as some kind of object which contains different data types. Instead create a class which makes it possible to write type safe code.

Related

Swiftui: how do you assign the value in a "String?" object to a "String" object?

Swiftui dictionaries have the feature that the value returned by using key access is always of type "optional". For example, a dictionary that has type String keys and type String values is tricky to access because each returned value is of type optional.
An obvious need is to assign x=myDictionary[key] where you are trying to get the String of the dictionary "value" into the String variable x.
Well this is tricky because the String value is always returned as an Optional String, usually identified as type String?.
So how is it possible to convert the String?-type value returned by the dictionary access into a plain String-type that can be assigned to a plain String-type variable?
I guess the problem is that there is no way to know for sure that there exists a dictionary value for the key. The key used to access the dictionary could be anything so somehow you have to deal with that.
As described in #jnpdx answer to this SO question (How do you assign a String?-type object to a String-type variable?), there are at least three ways to convert a String? to a String:
import SwiftUI
var x: Double? = 6.0
var a = 2.0
if x != nil {
a = x!
}
if let b = x {
a = x!
}
a = x ?? 0.0
Two key concepts:
Check the optional to see if it is nil
if the optional is not equal to nil, then go ahead
In the first method above, "if x != nil" explicitly checks to make sure x is not nil be fore the closure is executed.
In the second method above, "if let a = b" will execute the closure as long as b is not equal to nil.
In the third method above, the "nil-coalescing" operator ?? is employed. If x=nil, then the default value after ?? is assigned to a.
The above code will run in a playground.
Besides the three methods above, there is at least one other method using "guard let" but I am uncertain of the syntax.
I believe that the three above methods also apply to variables other than String? and String.

Creating dictionary of functions with symbols as keys

I am trying to create a dictionary of functions with symbols as keys but I am getting an error. I have tried the following:
functions = Dict{
:gauss => (v::Float64)->gauss(v, 0.0, 1.0),
:sin => (v::Float64)-> sin(v),
:nsin => (v::Float64)->(-sin(v)),
:cos => (v::Float64)-> cos(v),
:ncos => (v::Float64)->(-cos(v)),
:tanh => (v::Float64)->tanh(v),
:sigm => (v::Float64)->sigmoid(v),
:id => (v::Float64)->id(v)
}
The error I am getting :
ERROR: LoadError: TypeError: in Type, in parameter, expected Type, got Pair{Symbol,getfield(Main, Symbol("##105#113"))}
Please let me know what I am doing wrong. Thanks for the help in advance.
I figured the{} need to replaced by ().
As you found out your yourself, the {} brackets indicate type parameters whereas the paranthesis indicate a constructor call.
Note, that the ::Float64 type annotations aren't necessary for your functions to be performant. Think of them more as a user interface restriction; that is users won't be able to call your methods with non-Float64s. However, if you want to specify types explicitly, you could also specify the type of your dictionary explicitly as such Dict{Symbol, Function}(...). However, since you don't initialize the Dict empty, Julia will figure out the best type based on your input (symbol function pairs).

Why is my Map type not exported by Reason?

Following this question, I have created a file (and hence module) that defines a concrete Map type:
/* Scores.re */
module StringMap = Map.Make({
type t = string;
let compare = compare
});
type scores = StringMap.t(int);
Now, I want to use the type in another file:
/* Demo.re */
let currentScores = Scores.scores.empty;
Js.log(currentScores);
However, this gives me the error:
The value scores can't be found in Scores
If I add a constant (e.g. let n = 123; and Js.log(Scores.n);) then it works.
What am I missing here?
scores is a type, and types, even record types, do not have fields on the type itself. Furthermore, types and values live in different namespaces, so while the scores type exists, the scores value does not, hence the error "The value scores can't be found in Scores".
Modules, on the other hand, can have "fields", so that's why it lives there. And you could of course also alias empty the same way you've aliased the Scores.t type:
type scores = StringMap.t(int);
let empty = StringMap.empty;
Finally, you ask "Surely to make a Map instance the key-type must be known?". Indeed it does, and you've made it known. You specified the key type when you made the StringMap module (Map.Make({ type t = string; ...0);). You do not need to specify the value type (int), however. That will be inferred.

Understanding Elm's Type Signature return types

I am trying to understand elm's type signatures. What does this function return exactly? It appears to be a function that accepts no arguments and returns ...
route : Parser (Page -> a) a
As a learning exercise for myself I'm going to try to answer this. Others will chip in if I get something wrong.
I'm sure you are used to something like
type Person = Adult String | Child String Age
Child is a type that takes two parameters. Parser is the same. But it's definition is pretty formidable
type Parser a b =
Parser (State a -> List (State b))
type alias State value =
{ visited : List String
, unvisited : List String
, params : Dict String String
, value : value
}
That said, you see how Parser is ultimately a wrapper around a function from a State to a list of States. Ultimately it is going to be passed a List of 'unvisited' strings or params; it will progressively 'visit' each one and the result will be combined into the final 'value'.
Next, note that while Parser takes two type parameters - a, b - parseHash is defined
parseHash : Parser (a -> a) a -> Location -> Maybe a
So, your original
route : Parser (Page -> a) a
is going to have to be
route : Parser (Page -> Page) Page
to type check.
To return to your original question, therefore, route is a Parser (which is a very general object) that encapsulates instructions on how to go from one Page to another, and can be used - via parseHash - to tell you what Page to go to next, and that is of course what you would expect from a router.
Hope this gets you started

How do you emit to class that has a 'params' constructor?

Here is the definition of my Package class:
type Package ([<ParamArray>] info : Object[]) =
do
info |> Array.iter (Console.WriteLine)
member this.Count = info.Length
and here is the IL, I'm trying:
let ilGen = methodbuild.GetILGenerator()
ilGen.Emit(OpCodes.Ldstr, "This is 1")
ilGen.Emit(OpCodes.Ldstr, "Two")
ilGen.Emit(OpCodes.Ldstr, "Three")
ilGen.Emit(OpCodes.Newobj, typeof<Package>.GetConstructor([|typeof<Object[]>|]))
ilGen.Emit(OpCodes.Ret)
but this doesn't seem to work. I tried:
ilGen.Emit(OpCodes.Newobj, typeof<Package>.GetConstructor([|typeof<String>; typeof<String>; typeof<String>|]))
a well as:
ilGen.Emit(OpCodes.Newobj, typeof<Package>.GetConstructor([|typeof<Object>; typeof<Object>; typeof<Object>|]))
but it just laughs at me. What am I doing wrong?
The [<ParamArray>] attribute indicates to a compiler that a method accepts a variable number of arguments. However, the CLR doesn't really support varargs methods -- it's just syntactic sugar provided by the C#/VB.NET/F# compilers.
Now, if you take away the [<ParamArray>], what are you left with?
(info : Object[])
That is the signature of the constructor you're trying to call.
So, you'll need to use the newarr and stelem opcodes to create an array, store the values into it, then call the constructor using the array as the argument. This should do what you want (though I haven't tested it):
let ilGen = methodbuild.GetILGenerator()
// Create the array
ilGen.Emit(OpCodes.Ldc_I4_3)
ilGen.Emit(OpCodes.Newarr, typeof<obj>)
// Store the first array element
ilGen.Emit(OpCodes.Dup)
ilGen.Emit(OpCodes.Ldc_I4_0)
ilGen.Emit(OpCodes.Ldstr, "This is 1")
ilGen.Emit(OpCodes.Stelem_Ref)
// Store the second array element
ilGen.Emit(OpCodes.Dup)
ilGen.Emit(OpCodes.Ldc_I4_1)
ilGen.Emit(OpCodes.Ldstr, "Two")
ilGen.Emit(OpCodes.Stelem_Ref)
// Store the third array element
ilGen.Emit(OpCodes.Dup)
ilGen.Emit(OpCodes.Ldc_I4_2)
ilGen.Emit(OpCodes.Ldstr, "Three")
ilGen.Emit(OpCodes.Stelem_Ref)
// Call the constructor
ilGen.Emit(OpCodes.Newobj, typeof<Package>.GetConstructor([|typeof<Object[]>|]))
ilGen.Emit(OpCodes.Ret)
NOTE: In this code, I used the dup OpCode to avoid creating a local variable to hold the array reference while storing the element values. This is only feasible because this code is fairly straightforward -- I strongly suggest you create a local variable to hold the array reference if you want to build something more complicated.

Resources