Yes, agreed. I'd like to see a low-level language that makes this distinction cleanly with minimal syntactic noise and semantic confusion, but it seems tricky.
-
-
Replying to @shachaf
In a toy language, I used p^ and p:=p^+1 for reading and writing, p^.x and p^[0].x for reading and then accessing a field, and p.x and p[0] for obtaining a substructure pointer which looks just like an ordinary pointer. Super clean once one accepts the need for explicit reads.
1 reply 0 retweets 2 likes -
Replying to @TimSweeneyEpic @shachaf
The language also has a concept of first class failure, so that p^[2] can fail immediately if p^ has less than 3 elements, and p[2] which always succeeds but can then fail later when dereferenced in that case.
1 reply 0 retweets 4 likes -
-
Replying to @TimSweeneyEpic
Yes, I think this is the way to go if you make reads explicit. https://en.wikipedia.org/wiki/BLISS is close. I'd kind of like to avoid overloading "a.x" if possible -- it has different meanings for pointers and values, though it should be guaranteed that "(a^).x = (a.x)^".
1 reply 0 retweets 0 likes -
Replying to @shachaf @TimSweeneyEpic
I suspect something like that is unavoidable, though, and I should accept that a struct specifies not only memory layout (field-offset map) but value-level meaning (which is also used for calling conventions etc.). The alternative is C-style "." vs. "->" separation, I guess.
1 reply 0 retweets 0 likes -
Replying to @shachaf @TimSweeneyEpic
I'm a bit worried that code like "a[i^+j^] = min(a[i^]^, a[j^]^)" gets much less readable than "a[i+j] = min(a[i], a[j])" with too many dereferences, though I haven't programmed enough in this style to be sure.
3 replies 0 retweets 0 likes -
Replying to @shachaf @TimSweeneyEpic
(Also, if you have a "for (i in 1 to 10)" loop, and you want to change it to manual iteration, you have to change all the "i"s to "i^"s. I guess that's by design? But it seems awkward, just like changing "." to "->" everywhere.)
2 replies 0 retweets 1 like -
Replying to @shachaf @TimSweeneyEpic
I'm not sure I follow the failure example -- does a pointer "remember" which array it was indexed from and check at dereference time, rather than just being an address? Or is it some kind of effect system that tracks failure separately?
1 reply 0 retweets 0 likes -
Replying to @shachaf
In my implementation, a pointer is either a simple pointer to a top-level allocation, or a heap-allocated structure binding a simple pointer to a list of elements identifying its path. Another implementation could use interior pointers.
1 reply 0 retweets 1 like
The point of this is just that you can go from a pointer to an array to a pointer to an element without ever needing an lvalue using this syntax p[2] rather than C &(*p)[2].
-
-
Replying to @TimSweeneyEpic
I think I'd prefer to have the error definitely happen at indexing time. If an array is a thing that exists at an address, you'd presumably have something like operator[] : Ptr (Array a) -> Int -> Ptr a, but that operator should check bounds (rather than deref : Ptr a -> a).
1 reply 0 retweets 0 likes -
Replying to @shachaf @TimSweeneyEpic
By the way, I think even in a language like C it's useful to make a distinction between a struct primary used to specify memory layout (large, never used by-value) and one used as a value (small, by-value, has a canonical memory encoding but is often in registers etc.).
0 replies 0 retweets 0 likes
End of conversation
New conversation -
Loading seems to be taking a while.
Twitter may be over capacity or experiencing a momentary hiccup. Try again or visit Twitter Status for more information.