-
Notifications
You must be signed in to change notification settings - Fork 156
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Research spike for creating a new "dict" type #3158
Comments
Basic APIThe basic API of the dictionary type is the following
At the very least we need a function that instantiates a dictionary from a list of pairs. We need a way to lookup an element from a dict. And we also need a way to modify dictionaries by inserting and removing elements. Note this basic API does not require any new syntax. This means no changes to the parser/AST. We do however need to define a new parameterized type for dictionaries
This means the type system will catch errors such as the following
ImplementationImmutable maps are typically implemented using some form of balanced/unbalanced tree data structure. This keeps updates/inserts/deletes from having to do a full copy of the tree. Instead these mutations only require copying the search path. The rest of the tree can be shared. Ben Johnson has actually implemented a sorted immutable map type for which the underlying representation is a B+Tree https://github.com/benbjohnson/immutable#sorted-map. It's not clear just yet if this is the right implementation to use as the internal node size is 32 elements which means the size of a dictionary will need to be relatively large in order for operations to be efficient. In particular, modifying dictionaries fewer than 32 elements in size will involve a full deep copy. If this is too much overhead then we'll probably have to implement a persistent map ourselves. Regardless of the underlying implementation however, we'll need to create a new value type similar to the following type Dictionary interface {
Get(key int64, default: Value) Value
Insert(key int64, val: Value) Dictionary
Remove(key int64) Dictionary
Get(key string, default: Value) Value
Insert(key string, val: Value) Dictionary
Remove(key string) Dictionary
...
} Implementing func (ctx context.Context, args values.Object) (values.Value, error) {
key, ok := args.Get("key")
if !ok {
...
}
from, ok := args.Get("dict")
if !ok {
...
}
def, ok := args.Get("default")
if !ok {
...
}
switch k.Type().Nature() {
case Int:
return d.Get(k.Int(), def), nil
case String:
return d.Get(k.String(), def), nil
...
}
} Syntax for dictionary literals
Type inference will need to generate type constraints for this new syntax. For example, for the following literal
we need to generate the following constraints
We don't need to add any special type constraints since there's no ambiguity syntax-wise among dictionaries, records, or arrays. Syntax for accessing dictionariesI really like the syntax |
Two questions: On the sytnax for the literals would we support an identifier as the key? i.e. something like this For consistency should we call all the dictionary args
Should it be instead?
I like how |
I don't think so since it's not consistent with the type.
Yes I think you're right. |
Makes sense follow up question:
Would we let literals have a dynamic key?
|
Ah it seems I misunderstood your original question. Yes any expression that evaluates to (in this case) a string should be valid to use as a key value in a dict literal. |
This looks pretty straightforward, though it's clearly a bigger bite than I originally expected this to have. I was reading it thinking "could we create a kind of 'limited' dict? One that only has strings as keys?" Looking back at my notes, I saw that we did discuss this, and I just forgot.
This is the place where I feel kind of awkward. I think this is the right thing, but it could create some confusion with people working in other languages (javascript, for instance, has a real and actual adjacent problem). I guess the only thing I'm asking is that we make sure the missing identifier error here be helpful in explaining what happened here when one gets it wrong, but even saying that out loud, we could do to have friendlier error messages in a number of places. |
@rockstar That is a great point, we want to have a super clear error message for a missing identifier in this context that recommends the user use quotes. For example something like this (using the new syntax proposed in the PR #3317)
Or something like that. On a related note I found this a while back that is a Rust crate for providing helpful error messages with suggestion like this https://github.com/brendanzab/codespan |
OF COURSE there's a rust crate for nice error messages. 😂 I don't think I'd ever thought much about error messages as much as I have since writing rust regularly. |
insert
anddelete
get implemented as a first pass? There must be a path forward planned, even if not fully implemented.create
? Could the creation syntactic sugar look like this:[a: b, c: d]
createFromList
andcreateFromRecord
?createFromRecord
would require some reflection, so probably not.Nice to haves, but not required:
a = 1 obj[a]
? What is the impact on the type system, and is it even possible?DOD
The text was updated successfully, but these errors were encountered: