5 ms·
From a discussion we had about this paper, in the context of the relational logic language we are working on: Data abstraction is an interesting topic in a lan
by jamii 12y ago
From a discussion we had about this paper, in the context of the relational logic language we are working on:
Data abstraction is an interesting topic in a language that doesn't
really have data structures. ADTs are usually used to describe the
allowable operations on either a data structure or some side-effectful
system.
For describing data models, we have tables and (soon) integrity
constraints. An integrity constraint is a rule which aborts the
transaction if it produces any output. Simple integrity constraints
like column types and foreign keys can potentially be removed when the
compiler can prove that they will not be violated.
For derived data, rather than providing a method which returns the
desired information, we define a view on the data eg instead of a
getTotalSalary method we would define a rule that inserts data into
the totalSalary table which is then either lazily evaluated on query
or materialised and incrementally updated.
For modifying data we currently have no alternatives to directly
working on the base data. There is some amount of work on
bidirectional relational views but it seems like it adds a large
amount of complexity for a problem we don't currently have.
We do intend to make scalar values and functions extensible, similar
to http://www.postgresql.org/docs/8.3/static/xtypes.html http://www.postgresql.org/docs/8.3/static/xtypes.html
For side effects, we request actions by adding a row to a table that
has a watcher attached. The interface is described by the set of
tables available eg
jobs started (id, input data...)
jobs to be cancelled (id)
jobs completed (id, output data...)
http://db.cs.berkeley.edu/papers/eurosys10-boom.pdf http://db.cs.berkeley.edu/papers/eurosys10-boom.pdf and
http://db.cs.berkeley.edu/papers/vldb14-edelweiss.pdf http://db.cs.berkeley.edu/papers/vldb14-edelweiss.pdf describe
variations on this approach. Our current editor prototype uses the
Edelweiss model, which is my preferred choice if we can make it work
smoothly. The main difficulty so far is in constructing stable ids to
ensure that actions are idempotent.
In any case, for most protocols you need to constrain not just the
types of individual messages but the allowable sequences. ADTs don't
help here. Where the protocol can be described by a state machine we
can simply encode that state machine in a table and have a rule that
verifies message histories and provides a list of currently allowable
actions.
- seanmcdirmid 12y agoWhy would stable ids be a problem? Is it because immutability doesn't give you any stable references to latch on to?
- jamii 12y agoHave a look at the Edelweiss paper I linked. Stable ids are needed for that model. We would probably be fine with eg random uuids if we stuck with Bloom. EDIT: Thinking about it, the issue is definitely not that it is immutable but that it is declarative. In the absence of control flow, `new` is not sufficient to provide unique identity because the rule in question may be run zero or more times.
- seanmcdirmid 12y agoAlot of work in glitch goes into solving this problem. In the new case, we are able to form stable (reproducible) IDs through a memoized lexical stream (re-lex will produce the same tokens if possible) and by using the call stack (so the id is a path with special ids for loop indices). For a declarative (rule based?) language, perhaps rule firing context could be used for a similar purpose; I'll try to look at that paper and see if something clicks. I guess it depends on what makes a unique object. Though if you are completely declarative, why would object identities be necessary?
- jamii 12y agoFor largely the same reason that relational databases need identity. The classic example is the users table. Everything about the user, from their username to their email address, can be changed. So you need some way to stably reference that user. In the timeless Tarpit/Edelweiss world, the current state of the program is a pure function of its inputs. That means that the id has to be deterministically derived from the inputs. For now we synthesise ids out of contextual information eg "the user created at time T by event X". This works for now but it feels a little awkward. Once we have written more code in Eve we will have a better set of examples to guide thinking about a solution.
- seanmcdirmid 12y agoIsn't that effectively mutation then? You have an ID with information related to that ID that changes, or what we would call mutable fields in the object world. Anyways, this is why I don't play with declarative programming models anymore: I would wind up hacking in necessary things like identity and mutation in very weird ways. This is why I decided instead to try applying declarative time semantics to an imperative programming model. Your solution is quite similar to mine: all blocks that continue in after clauses underneath an event are indexed by the event instance (we memoize event instances so they have identifiers). One problem that we had to deal with is the discrete nature of an event handling context; it made sense to have an additional clause that continues after the event (to create an object like a new user) vs. code that executes discretely (like a physics step). The former gets indexed by the event instance, the latter is shared across all event instances (so you can't really create an object in anything other than a top-level block of event-after block).