-
Notifications
You must be signed in to change notification settings - Fork 174
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
[feature] better support for storage and type qualifiers #1394
Comments
One downside to supporting type qualifiers through If we defined
In either case, it's impossible to construct a value of the type ex nihilo directly in a declaration. Neither of these options is especially ergonomic and might be a nudge toward implementing more elegant support for this in the compiler. Also; I haven't thought about what implications the type qualifiers have for the borrow checker on the Carp side, if any, but if if they do that would be another reason to implement support for them directly into the compiler. |
C supports a couple of different type and storage qualifiers which have significant impact on its semantics, such as
const
,volatile
,static
,extern
.Currently, there are only two ways to emit these sorts of qualifiers from Carp:
annotations
meta field to annotate bindings with qualifiers. This is currently only supported fordefn
forms.Both methods are fine, but lead to some clunkiness, for instance, it's currently impossible to declare a Carp function that takes a
const
qualified argument, without using some type trickery; one has to register the "constant variant" of a type e.g.(register-type ConstInt "int const")
) or resort to defining the function as a template. This is unfortunate, since it means there's a whole class of functions that, though expressible in plain Carp, need to be written in C or using some kludge just because of a type qualifier at interface boundaries.Furthermore, the placement of some qualifiers, such as
const
matters:int const *
: (non-const) pointer to constant intint* const
: constant pointer to a (non-const) intint const * const
: constant pointer to a constant int.The current situation also makes it quite difficult to qualify Carp's generic types. For example, I can't think of how one could const qualify the C type corresponding to a Carp generic using the current approaches without either knowing exactly what name the compiler will generate (brittle) and using this information to write a correct
deftemplate
.In order to better support this, we can do a few things:
annotations
meta support. As mentioned, the value of this field is currently only emitted for function declarations. It should be emitted for variables (def
forms) as well. Additionally, the annotations mechanism currently emits the annotation on the left of the declaration. This breaks the "read right to left" rule for complex declarations and could make it difficult to anticipate what will happen. At the same time, it is the necessary placement for storage qualifiers likestatic
.Should produce the declaration:
And
Should produce:
(static foo)
, assumingfoo
is already defined andstatic
is a special meta macro that sets astorage-class
field, should produce:How should we implement this?
I think some combination of all three points considered above would be best, that is, I'd propose we:
annotations
meta to apply to all declarations, keep it maximally flexible to allow users to add whatever qualifiers they want, with the understanding that its behavior is to place the qualifiers immediately to the left of the declaration. This is great in that is allows users to emit qualifiers that may not yet be supported by more direct means in Carp, may be bound to weird macros, etc.<T> const
and<T>
as distinct, and complain if you attempt to use one in the position of another. Since we have a stronger type system in carp, I think it makes sense to define this at type-level. Furthermore, we need to recognize that, unlike storage class qualifiers, type qualifiers may appear on declarations and in function parameter positions—they are effectively proper types. Using higher-order types for this leads to the very natural syntax:(sig foo (Fn [(Const (Ptr Int))] Unit))
Contrarily, if we attempted to use meta information for such qualifications, what would define the meta on? The type itself? That wouldn't work, for then all
(Ptr Int)
would becomeint* const
. On the function parameter names and declarations? That would also be a bit bizarre as we don't currently support meta on parameters and the type checker would need to start consulting the meta of every binding to make sure the type is actually the given type and not a qualified type.One can also then coerce to const/non-const types where needed, just as is sometimes necessary in C when calling across functions that have different const expectations (typically the programmer needs to confirm the non-const function doesn't modify the data):
(the (Const (Ptr Int)) (address foo))
.To this end, we should add the following compiler-backed special type-qualifier types:
(Const a)
: emits<a> const
(Volatile a)
: emits<a> volatile
(Restrict (Ptr a))
: emits<a>* restrict
Then, the carp type checker will also align with a good C compiler and complain about using a non-const type in a const position. Note that
restrict
is only valid for pointer types. We could also make restrict valid for the other reference typesRef, Box
by defining it as a sumtype.annotations
under the hood once annotations are exteneded to support def declarations. e.g.(extern foo)
emitsextern <T> foo
.As an alternative to (2.) we could extend
register-type
to support template style generics, and then define a qualifying type likeConst
as:(register-type (Const a) "$a const")
. This may be better insofar as it decouples this feature from the compiler. It would also permit users to declare a "left side" variant if needed(register-type (ConstLeft a) "const $a")
. This would also take an approach that already works for specific types(register-type ConstInt "int const")
and extended it to make things easier/more flexible.The text was updated successfully, but these errors were encountered: