-
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
Proposal for incorporating explicit state intialization and association #22
Comments
Thanks @JustusAdam for putting together this proposal. This one is very important, so we should understand what that is conceptually. I see this as an introduction of a special type into our language. One can view it like this: There exist two (higher-kinded) types in our system
More formally, "stick" means that this function actually turns a function I like the discussion above about making the state aspect obvious to the programmer in two places:
But after all, we are talking about a type-system aspect here, so if the programmer gets guided by the compiler then making it only obvious during creation is fine for me. |
A short note on how I implemented this:I am currently in the process of implementing this both in the compiler and the parsers. |
Refactored old code to comply with the removed `Sf` pattern
Fixed the `Arcs` type (now compound, direct and state arcs are separated) Changed the `Arc` family of types (its a single `Arc` type now and the rest aliases) Implemented passes necessary for state binding normalization Also simplified the other inlining passes using compositions of smaller passes Changed `DFFnRef`. It makes more sense now Extended the DFLang parser to work with state args
I have the basic implementation in place. We will follow up aspects such as shared state etc. in other issues once we get there. |
Problem description and solution requirements
The Rust backend for Ohua requires an explicit association between the state of
a stateful function and the function itself. As a relic from Java this has up to
this point been implicit (as a class) or linked using a backend mechanism such
as clojure metadata.
This implicit approach is unfeasible in Rust, because the implicit association
of a class is not present, and more importantly the reflection mechanisms for
discovering initializers for state do not exist.
Furthermore we believe that an explicit state association will provide more
flexibility for the user and may be used to implement state sharing stateful
functions.
Requirements
which functions have state
the backend does not require reflection to find it.
Additionally our proposals so far are also designed such that they may be used
in the future to express state sharing. While this is not a necessary property
to solve the issue at hand, it is a desirable property.
Solution variants
We believe that new syntax may be necessary to implement state initialization and
association in a user friendly way.
Three variants were discussed so far.
Arrow assignment with implicit association
In arrow syntax a special new assignment operator
<-
(or similar) is used toexplicitly initialize a state cell. This binding (
s
in the example) canonly be used as a first argument to a stateful function and implicitly
associates as the
statefulFunction
's state.Advantages
smap
), which will make itpossible in the future to do dynamically created/auto resetting state
s
can be supplied to multiple functions, allowing statesharing.
Disadvantages
Possible confusion over the fact
s
cannot be used in the same way otherbound values can, despite seeming to be a regularly bound value.
The operator
<-
is not self explanatory. It bears no inherent associationwith state as such.
<s-
arrow.Scoped intialization does not exist yet which means we have to require users
to bind the state in the outermost scope so that their code does not subtly
break one we introduce the feature. However doing this is tedious, especially
in the presence of algorithms, where having to explicitly provide state not
only bloats code, but to me also feels like leaking implementation detail.
Env
arg). This can be enforced via the compiler. As such, an algorithm can have its own initializers.Even in the presence of scoped bindings we may want to provide additional
syntax for locally initializing state that is automatically bound at the
outermost scope with the very reasons just mentioned.
Implicitly associating state via the first argument of a function makes it
less obvious for the user whether a function is stateful or not. Rather than
being able to tell immediately from the syntax, one has to find the binding
site for the first argument and consider its "type"
State a
type. As such, finding out whether this is state or not is no harder than fixing any other type error. It is essentially the same problem for the programmer.Finding which functions share state requires tracking down the use sites of
s
.with
operator (explicit initializer association)The
with
operator associates a state initializer with a function.with
is abinary operator and its rhs must be a callable expression in the target
language1. State sharing is done by either reusing an
already bound function (
boundSf
) or initializing multiple stateful functionswith the same function (
function1
andfunction2
).1: The precise nature of the RHS is variable. We can use
a function or maybe even expression, which would allow for dynamically created
state.
Advantages
state cells cannot be confused with other
let
bound values.whether the function is stateful or not. No need to chase down the binding
site of the first argument.
with
always binds state globally, thus no need to pay special attention tothe future possibility of scoped state.
sharing a particular state.
Disadvantages
local
keyword to scope state binding.let boundSf = statefulFunction with local initState in ...
.with
feels somewhatless flexible than using
<-
.with
is to make state sharing more explicit but then it is possible to just use those created functions in different places. So, I essentially have the same problem again, such that we did not solve the problem of finding all function calls that share state in one place.Regular
let
with explicit state associationThis variant is a blend of
<-
andwith
. It explicitly associates a statecell with a stateful function using
on
. However unlikewith
it allowsbinding the state cell earlier using
let
which enables state sharing by usingthe bound state with multiple functions or using an
on
bound function multipletimes.
Depending on the availability of dynamic state binding and scoped state certain
restrictions may be placed on what the RHS of
on
has to be. For instance, inthe beginning we require that it resolve to an env binding.
Advantages
<-
variant state can be bound in scopes. Enabling dynamic statebinding and scoped state.
s
.with
stateful functions are easy do distinguish from stateless ones,because
on
occurs at the use site.Disadvantages
s
are unclear with respect to whether it is usable as aregular value. It is unclear whether it can or should be allowed to be used as
regular data. If not, this may also lead to the same confusion as was the case
with the arrow variant.
s
.On new syntax
I think it is worth mentioning that we may not necessarily require actual new
syntax for this feature. A similar effect may also be achieved by using a
function (such as
init
) that is especially recognized by the compiler.Similar as with
<-
init
values would be traced through the code andimplicitly become the state of a function to which they are the first argument.
The same advantages and disadvantages as with
<-
apply.One advantage of this approach over all the others is that no new syntax needs
to be introduced. This means that handling
init
can be entirely done in thecore library with no change to any of the parsers.
As a disadvantage, there can not be a stateful function named
init
, similar to thenew
keyword in languages like Java.The text was updated successfully, but these errors were encountered: