This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2018-07-21
Channels
- # beginners (55)
- # cider (13)
- # cljdoc (4)
- # cljsjs (1)
- # clojure (11)
- # clojure-spec (7)
- # clojure-uk (9)
- # clojurescript (42)
- # docs (5)
- # figwheel-main (9)
- # fulcro (4)
- # graphql (4)
- # hoplon (27)
- # keechma (32)
- # leiningen (11)
- # luminus (2)
- # nyc (2)
- # off-topic (73)
- # parinfer (1)
- # re-frame (36)
- # reagent (2)
- # reitit (6)
- # ring-swagger (3)
- # shadow-cljs (51)
- # spacemacs (4)
- # tools-deps (17)
- # uncomplicate (1)
So i've started developing a scripting language closely tied to clojure data structures, and i've kind of hit a roadblock. In the language, I want to support indexing facilities similar to languages like javascript, python, and lua while maintaining the persistent data structures. However! I also want to include metaprogramming facilities to overload this functionality. This unfortunately makes things much more complicated.
For example, something like: x = {:a {:b {:c 42}}
could be accessed like so: x.a.b.c
, which could then also be assigned to in a similar fashion: x.a.b.c = 43
. This would then support overloading these facilities through prototype-based metafunctions. ie. setmeta(x {__index (function (this key) return this[key] end)})
The problem is nested associations to inner data. I'm assuming that languages like python, lua, and javascript depend on referencing to simplify the resolution, but I can't seem to wrap my head around how I could go about supporting the same functionality using persistent data structures that are each immutable.
So i'm looking for suggestions on how I might go about supporting this, or if it's even possible? I was thinking of adopting some sort of navigator system in order to tag the hashmaps which could be hidden behind the scenes. Another approach would be to somehow adapt the clojure types into weak referenced types, but I feel like this would be a lot of work for not much gain.
Another possibility is to forget the association functionality, and adopt more of the clojure approach
I think indexing could still easily be supported, the problem really seems to be association
but this would tie into indexing, since I feel like i'd have to maintain some sort of navigator when progressing through the data structure in order to effectively re-associate a variable
once you change something deep in a data structure, the root has also therefore changed
so what are the semantics of =
i'll just post the github repo, things are still in the early stages so certain semantics could change
if you have x = {:a {:b {:c 42}}, then y = x, then x.a.b.c = 43, what does y have?
so far, I still need to implement the data accessor and getter stuff, metamethods, and module
y will store x, ie. (= x y), however, I was hoping that when I change y, it would not be a reference to x
I had some ideas, but it would be less expressive. For example, how would I deal with something like x.y.getInstance().z = 43 ?
it would be impossible with persistent structures, unless there's something i'm missing
hmm, what functionality do you mean with "weak referencing"? these issues are about resolution, but weak references are really specifically about gc, not the broader spectrum of resolution.
do you know the spectre library?
yeah- i don't want to get hung up on it
it sounds like there are questions about semantics- like, are there immutability semantics, or copy on write semantics
so in python, when you create a dict, and I associate x = {}, and then say y = x; y["a"] = 1, both x and y still store a reference to the same data structure, right?
yes, python not immutable
so if I say x = {}, and y = x, manipulating x will not affect y. There is no relationship between them at that point
yup, got it. so a copy on write scripting language
I could definitely do this without using the association techniques they use in lua, python, javascript
yes- there is a valuetypes vs referencetypes distinction there
I was hoping to play closer to a scripting language that acts like lua, so it's possible that i'll have to pass around references instead. I just can't imagine that being straightforward lol
well, the thing is that some of the difficulties you're referring to are optimizations. the simplest thing is that when you perform assignment (or association), to just make a copy
copy on write is an optimization allowing for lazily sharing the same value
This might be an implementation problem on my part, since I have no way of referencing some deeply nested cases
However, if I just adopted a reference model of doing things. I could evaluate the chain on the left side to obtain the reference, and associate directly
well- these concerns are only issues if you have more than one thing pointing to the same data structure/resolution root
and/or permit concurrent access
yes, but only if I value those semantics. I don't mind if x and y did in fact share the reference. I'm working within the constraints of how clojure handles these types
In fact, if someone had a library that implemented the clojure data structures with referencing in that manner, i'd probably jump on it and use that instead haha
hmm, i don't follow- doesn't spectre do exactly this thing? allow for function application to deeply nested elements of a data structure?
giving you back the data structure following the results of that application?
yes- spectre is basically more ergonomic and capable zippers. to a first approximation, it might be interesting to do a translation of your syntax into spectre navigation, see if there is alignment. i would think that eval would not be needed, but don't know. it would be nice to have a fast starting copy on write scripting language, can't think of one in that space
Alright, spectre it is, I think the method call resolution wouldn't be an issue either since it could also return it's own separate navigator. I'll look into maybe tacking on additional navigation data when I pass around data. A copy on write scripting language would be interesting if it works out lol
sounds cool, good luck!
So I just thought about it some more, and I am overcomplicating it. The concept of a call on the left side of the association doesn't make sense, since you would do that if you were returning a 'reference' Since i'm never returning references, and i'm always doing copy-on-write, it doesn't make sense, so I simply won't support it.
gotcha, though it is an interesting use case- a syntax that supports dynamic navigation along with nested modification. it seems like it doesn't necessarily have to imply reference semantics- if there is no other way to use the root thing under which the navigation is taking place- e.g. if there is no concurrency, and prior assignments/associations to the root thing are already decoupled from it (for lack of a better term)- you don't lose the copy-on-writeness. each statement basically takes the world and creates a new world. anyway- it's your language, you can just decide on the semantics and on the syntax which most pleasingly gets there. 🙂
Yeah, i'm still exploring the idea of spectre, it would be interesting to include it's functionality as a first-class feature with it's own syntax sugar
will go into thread