-
Notifications
You must be signed in to change notification settings - Fork 1.5k
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
improve abstraction for AssocList, fix bug in optional else #315
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is definitely an improvement!
I left lots of detailed comments, many of which I don't expect to be addressed in this PR. Some I feel a little strongly should be addressed (e.g. keeping Cons
private and out of APIs), but mostly I've said a lot so you can understand how I'm thinking about readability and the future. So please feel free to argue with me, defer improvements to later PRs, etc.
@@ -21,8 +21,8 @@ namespace Carbon { | |||
|
|||
State* state = nullptr; | |||
|
|||
auto PatternMatch(Value* pat, Value* val, Env*, std::list<std::string>*, int) | |||
-> Env*; | |||
auto PatternMatch(Value* pat, Value* val, Env, std::list<std::string>*, int) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
While you're in here, it would be great to have a comment explaining what this function does, and especially the difference in meaning between returning a null optional and returning the 3rd parameter unchanged (or an empty Env
). I realize comments are a whole project unto themselves, but the problem is, without the comment, any change becomes very difficult to review, and you're the only one who knows this code.
(N.B. I would always give the parameters names that can be referred to in the comment.)
V value; | ||
AssocList* next; | ||
}; | ||
auto Extend(const K& k, const V& v) -> void { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't know if extend is a good name for this. It writes a new association, replacing any existing one for k
, right?
If this were swift, it would be easy and idiomatic to write it as the setter for a subscript. In C++, I dunno, SetValueAt
is the best name I can come up with.
auto Extend(const K& k, const V& v) -> void { | |
auto SetValueAt(const K& k, const V& v) -> void { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Extend is the name from the PL literature, but I can see that the name by-itself doesn't really convey the right meaning. I like your suggestion.
namespace Carbon { | ||
|
||
template <class K, class V> | ||
struct AssocList { | ||
AssocList(K k, V v, AssocList* n) : key(k), value(v), next(n) {} | ||
class AssocList { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As long as we're reshaping this, how about this?
class AssocList { | |
class Dictionary { |
return alist->value; | ||
} else { | ||
return Lookup(line_num, alist->next, key, print_key); | ||
auto Extending(const K& k, const V& v) -> AssocList<K, V> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
auto Extending(const K& k, const V& v) -> AssocList<K, V> { | |
auto SettingValueAt(const K& k, const V& v) -> AssocList<K, V> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Another problem with Extending(k, v)
is that it reads like it's extending k
.
CheckAlive(v, exp->line_num); | ||
frame->todo.Pop(); | ||
frame->todo.Push(MakeValAct(v)); | ||
auto a = CurrentEnv(state).Lookup(*(exp->u.variable.name)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
perhaps another place where auto
isn't helping.
auto a = CurrentEnv(state).Lookup(*(exp->u.variable.name)); | |
Address a = CurrentEnv(state).Lookup(*(exp->u.variable.name)); |
Or is that
auto a = CurrentEnv(state).Lookup(*(exp->u.variable.name)); | |
optional<Address> a = CurrentEnv(state).Lookup(*(exp->u.variable.name)); |
?
Though if I knew what a
meant (its role) it probably would have been fine, e.g.
auto a = CurrentEnv(state).Lookup(*(exp->u.variable.name)); | |
auto variableStorageLocation = CurrentEnv(state).Lookup(*(exp->u.variable.name)); |
frame->todo.Pop(); | ||
frame->todo.Push(MakeValAct(v)); | ||
auto a = CurrentEnv(state).Lookup(*(exp->u.variable.name)); | ||
if (a) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Suggests we want some kind of unwrapOrError
abstraction for optionals or better yet env.ValueAssertedAt(k, closureThatFormatsTheErrorMessage)
. C++ sure is clumsy at this.
Value* v = state->heap[a]; | ||
frame->todo.Pop(1); | ||
frame->todo.Push(MakeValAct(v)); | ||
auto a = CurrentEnv(state).Lookup(*(exp->u.variable.name)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
auto a = CurrentEnv(state).Lookup(*(exp->u.variable.name)); | |
Address a = CurrentEnv(state).Lookup(*(exp->u.variable.name)); |
@@ -1141,16 +1162,17 @@ void HandleValue() { | |||
Value* v = act->results[0]; | |||
Value* p = act->results[1]; | |||
// Address a = AllocateValue(CopyVal(v)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unexplained commented out code is more harmful than helpful IMO
// Address a = AllocateValue(CopyVal(v)); |
@@ -660,16 +664,16 @@ auto TopLevel(std::list<Declaration*>* fs) -> std::pair<TypeEnv*, Env*> { | |||
|
|||
auto FunctionDeclaration::TopLevel(ExecutionEnvironment& tops) const -> void { | |||
auto t = TypeOfFunDef(tops.first, tops.second, definition); | |||
tops.first = new TypeEnv(Name(), t, tops.first); | |||
tops.first.Extend(Name(), t); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is confusing; we're associating t
with the empty Name
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Name() isn't empty... that's a getter method that you defined... so that's the name of the choice.
…that use pointers, shouldn't have been there yet
I'm going to address Dave's comments in a subsequent PR... I forgot to make a branch for this one so I'm not sure how to update it... |
* improve abstraction for AssocList, fix bug in optional else * add flag for tracing output, clean up code for output * turned off tracing by default, updated goldens, removed two examples that use pointers, shouldn't have been there yet
Created a persistent map abstraction for AssocList, replacing the low-level cons abstraction.
Also fixed a bug in the interpreter regarding optional else clause of an if statement.
I had forgotten to update HandleValue in a previous commit.