mcoblenz / Obsidian

Obsidian language development
BSD 3-Clause "New" or "Revised" License
77 stars 10 forks source link

Add support for Obsidian state constructors #28

Open mcoblenz opened 7 years ago

mcoblenz commented 7 years ago

We have contract constructors, so I think we should probably make the state transition syntax look more like invoking a constructor, and then support that properly (rather than ->S1({x = 3, y = 2}) ).

tyleretzel commented 7 years ago

Can we discuss the pros and cons of this before committing to this? Maybe this is something to discuss with Jonathan/Josh/Brad. The advantage of constructors for the entire contract seem to be that they

1) document the starting state (or possible starting states), and 2) allow encapsulation, in the sense that the constructor can abstract away the details of how data is represented in the contract (i.e. "what fields are there?").

For state-specific constructors, I can see the latter use case being applicable in some cases, but I don't think there's as strong of an argument from the point of view of encapsulation, because states (by virtue of sharing at least the contract-wide fields) cannot be as encapsulated from each other to such a degree.

What is your thinking about this? Is there a particular example you have in mind where state-constructors are really helpful?

mcoblenz commented 7 years ago

My argument is in terms of consistency and modularity. I see these benefits of state constructors:

  1. Consistent syntax for object initialization. "Why do I need constructors for contracts but a totally different syntax/mechanism for states?"
  2. Non-trivial initialization: perhaps some work needs to be done when entering a state other than just setting fields, or even setting fields may involve some nontrivial computation that occurs in each transition to a given state. e.g. initializing a cache or informing a third party of the transition.
  3. I think there are modularity advantages of isolating states from each other as much as possible. For example, suppose I realize that every time I enter state S, I need to set a contract-level field appropriately. If I rely on the transition invocation to do that, I might miss a case; and future transition invocations may miss it too. It's better to encapsulate all the logic around a state transition somewhere that is centric to the target state, rather than distributing that to all of the places that invoke the transition.