-
Notifications
You must be signed in to change notification settings - Fork 0
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
NullRefException in CollectAtoms if Expansion(Exp e, string) called with e != Exp.Atom #25
Comments
When I was writing the code originally, I think the intention was that there would be certain constraints around The Am also wondering if this would be a good candidate for using static factory/builder methods to construct instances and maybe make the constructors protected or private so that the only way to get subtree expansions is to go via the expected interface, rather than running into this. Expansion exp = Expansion.Create(Exp.Expression, Expansion.CreateAtom(term)); Not particularly smart or elegant but does hide the need to care about the |
It really does seem like I need to sketch out a specification for the result objects as I can see the missing details and lack of clarity around the original dynamically typed recursive array implementations is going to have ongoing friction in C# (and similar, if we decide to port Calyx to C++ or Rust etc for Unreal in future, the same problems will repeat in that context too). I haven’t explored this yet, but I have been mulling over the idea of being able to generate enums and structs in addition to text, as that would be a huge value-add for Unity projects, in terms of being useful for statblocks, procgen weapons, magic spells, etc. Would be doable with some ugly hacks to Also wonder about letting people do something like But yeah, this is just speculative sketching and haven’t really thought it through. I can see how some more robust thinking around the way the expansion tree works could be beneficial and lay the ground work for this. |
After our discussion in #21 I was thinking making Expansion abstract and having a two subclasses for Atom and NonAtom expansions (Strategy pattern) //Expansion.cs (Abstract)
protected virtual void CollectAtoms() { }
//Atom.cs, inherits Expansion
public readonly string Term;
protected void CollectAtoms(StringBuilder sb) {
sb.Append(Term);
}
//NonAtom.cs (Abstract, inherits Expansion, all nonatom classes inherit)
public List<Expansion> Tail;
protected void CollectAtoms(StringBuilder sb) {
Tail.ForEach((t) => t.CollectAtoms(sb)
} This should probably stop most foot-guns without needing a factory |
Thanks, I was hoping you would articulate your thoughts on that. It makes a lot more sense just to go with the flow and use polymorphic dispatch, rather than trying to wrangle constructors to maintain invariants. |
Wish I hadn't opened my mouth. I started refactoring all this and put myself straight in a world of pain because I underestimated it all and should have planned more. I thought I was clever writing Assert.That(exp.Symbol, Is.EqualTo(Exp.Template));
Assert.That(exp.Tail[0].Symbol, Is.EqualTo(Exp.Memo));
Assert.That(exp.Tail[0].Tail[0].Symbol, Is.EqualTo(Exp.UniformBranch));
Assert.That(exp.Tail[0].Tail[0].Tail[0].Symbol, Is.EqualTo(Exp.Template));
Assert.That(exp.Tail[0].Tail[0].Tail[0].Tail[0].Symbol, Is.EqualTo(Exp.Atom));
Assert.That(exp.Tail[1].Symbol, Is.EqualTo(Exp.Memo));
Assert.That(exp.Tail[1].Tail[0].Symbol, Is.EqualTo(Exp.UniformBranch));
Assert.That(exp.Tail[1].Tail[0].Tail[0].Symbol, Is.EqualTo(Exp.Template));
Assert.That(exp.Tail[1].Tail[0].Tail[0].Tail[0].Symbol, Is.EqualTo(Exp.Atom));
Assert.That(exp.Tail[2].Symbol, Is.EqualTo(Exp.Memo));
Assert.That(exp.Tail[2].Tail[0].Symbol, Is.EqualTo(Exp.UniformBranch));
Assert.That(exp.Tail[2].Tail[0].Tail[0].Symbol, Is.EqualTo(Exp.Template));
Assert.That(exp.Tail[2].Tail[0].Tail[0].Tail[0].Symbol, Is.EqualTo(Exp.Atom));
string firstTerm = exp.Tail[0].Tail[0].Tail[0].Tail[0].Term;
string secondTerm = exp.Tail[1].Tail[0].Tail[0].Tail[0].Term;
string thirdTerm = exp.Tail[2].Tail[0].Tail[0].Tail[0].Term;
Assert.That(new[] { firstTerm, secondTerm }, Is.All.EqualTo(thirdTerm)); Was hoping to get a PR to you today that fixes this bug (the very very long way) but not so sure now |
The constructor leaves
Tail
asnull
, which eventually crashes inCollectedAtoms()
Should
Expansion(Exp, string)
create an empty list, orAssert(symbol == Exp.Atom)
?The text was updated successfully, but these errors were encountered: