"[...] Project, like many types in Roslyn, is immutable. When we add a Document to a project, we aren’t changing [the] project. We create a new one that can be accessed through the new returned Document. This snippet illustrates the example.
1 var doc = project.AddDocument("TestFile.cs", cSharpText);
2 Debug.Assert(!project.ContainsDocument(doc.Id));
3 Debug.Assert(doc.Project.ContainsDocument(doc.Id));
Roslyn confused me when it threw away my changes until I would notice the return type of the method and realize that adding a document doesn't modify a project but creates a new one."
I love functional datatypes, but this is a poorly designed API.
First off, functional new-version operations -- that return a new instance rather than modifying the existing one in place -- should when possible be named with nouns or prepositions rather than verbs. For example, the addition operation on Java's BigInteger should be named 'plus', not 'add'. If you write
x.add(y);
and don't happen to recall that BigInteger is a functional type, it's easy to assume that this statement modifies 'x' by adding 'y' to it. But if you write
x.plus(y);
the name itself suggests that this is an expression whose value you care about and want to assign to a variable instead of discarding.
I would have called this operation 'WithDocument' rather than 'AddDocument'.
And secondly, having this operation return the document rather than the new project seems a bit weird. I see the reason for it -- the new document object is being created at the same time from the source file supplied -- but it would be cleaner for this to be two operations (create the document, then create the new version of the project). If that doesn't work for some reason, I would use an out parameter to return the new document.
1 var doc = project.AddDocument("TestFile.cs", cSharpText); 2 Debug.Assert(!project.ContainsDocument(doc.Id)); 3 Debug.Assert(doc.Project.ContainsDocument(doc.Id));
Roslyn confused me when it threw away my changes until I would notice the return type of the method and realize that adding a document doesn't modify a project but creates a new one."
I love functional datatypes, but this is a poorly designed API.
First off, functional new-version operations -- that return a new instance rather than modifying the existing one in place -- should when possible be named with nouns or prepositions rather than verbs. For example, the addition operation on Java's BigInteger should be named 'plus', not 'add'. If you write
and don't happen to recall that BigInteger is a functional type, it's easy to assume that this statement modifies 'x' by adding 'y' to it. But if you write the name itself suggests that this is an expression whose value you care about and want to assign to a variable instead of discarding.I would have called this operation 'WithDocument' rather than 'AddDocument'.
And secondly, having this operation return the document rather than the new project seems a bit weird. I see the reason for it -- the new document object is being created at the same time from the source file supplied -- but it would be cleaner for this to be two operations (create the document, then create the new version of the project). If that doesn't work for some reason, I would use an out parameter to return the new document.