Convincing the compiler that some storage is initialized #1241
kyouko-taiga
started this conversation in
Language design
Replies: 1 comment 3 replies
-
For system programming, the
Imagine that (for some reason) I want to implement an Array that has local storage and doesn't do heap allocation. In that case, the memory layout would be something like [size, e1, e2, e3, ..., e100]. To initialize such an object, we only need to touch the bytes for the |
Beta Was this translation helpful? Give feedback.
3 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
-
/cc @dabrahams @lucteo
It's been discussed in Teams meetings that Hylo should have a way to get a pointer to uninitialized storage that can be used for initialization. The main use case is to be able to initialize a piece of memory using a foreign function. For example:
It is impossible to write such a program in Hylo today. As noted by @dabrahams in #1239:
It seems like Dave and I now agree that the feature we really want, at least for the time being, is only the one that lets us implement a Hylo function in C.
@ffi
does not address this goal because the purpose of this feature is to automatically write the glue code mapping Hylo's types to their C counterparts (e.g.Int8
->char
) and adapt calling conventions. Instead, what we want is to let the compiler assume that the body of a function declared in Hylo can be implemented externally and provided at link time.If we still wanted the ability to "convince" the compiler that something is initialized, we could add an the unsafe primitive to do that (see my answer in #1239), but I think it is unnecessary. I'd like to explain why in case we revisit this topic in the future.
First, I consider the feature very unsafe because it can easily violate assumptions that are harder to break with other unsafe operations. If you can convince the compiler that some stack-allocated memory is initialized, it will run a deinitializer at the end of its useful lifetime. That is unlike dynamically allocated memory that you have to babysit until you decide it can be reclaimed. In other words, I believe that one takes on more responsibility when they write
PointerToMutable<T>.allocate(count: n)
than when they writevar x: T[n]
, and this extra responsibility justifies the additional control one gets.Second, if we put language interoperability aside, I am not convince there are enough compelling use cases for this feature. Most of them are covered by
Union<A, B>
which can do the job safely and probably more efficiently, in part because in general one doesn't have intimate knowledge about the memory layout ofA
andB
and in part because we can teach the compiler about the semantics ofUnion<A, B>
. The exception would be the cases where one can dispense with the discriminator because some other part of their business logic can decide what's in the union. Those cases exists, but I think one should write them using buffers of bytes. Existing examples include our UTF8Array.We can also imagine writing some helper types around this idea, or come up with a list of recipes for developers on a bit budget. The following shows how one can implement a type whose payload can be initialized later without compiler oversight. Few features are missing to compile it, all are on the roadmap.
Sure, your code will have to deal with
DeferredInitialized<T>
rather than justT
but I think the notional indirection is justified. It compels you to think more carefully about the initialization state of the payload when you want to interact with it and when your instances go out of scope. The memory reinterpretation shenanigans could also probably be optimized away.Beta Was this translation helpful? Give feedback.
All reactions