D needs a type expression syntax
Quirin Schroll
qs.il.paperinik at gmail.com
Sat May 6 15:55:22 UTC 2023
On Friday, 5 May 2023 at 02:30:32 UTC, Basile B. wrote:
> On Thursday, 4 May 2023 at 15:40:20 UTC, Quirin Schroll wrote:
>> **TL;DR:** If we make `TypeCtor` optional in the production
>> rule `BasicType` → `TypeCtor`**`(`**`Type`**`)`**, the D type
>> grammar can be improved and we have a way to solve the
>> 14-year-old [issue
>> 2753](https://issues.dlang.org/show_bug.cgi?id=2753).
>>
>> [...]
>
> Wouldn't making `ref` a `TypeCtor` solve the issue more simply?
Technically, the answer is yes, but practically and
realistically, the answer isn’t just no, it is: absolutely not.
> While using parens is the natural way to disambiguate two
> different constructs, it seems that the only case that causes a
> problem is that we cannot express "return by ref" in function
> types.
That was the starter. I looked at various ways you could express
that. I’m convinced I once wrote a forum post asking for opinions
on a syntax to propose, but now I cannot find it anymore (and
that makes me doubt my memory). At some point, it randomly
occurred to me that making D’s type syntax an expression syntax
might naturally solve this – and working it out, it turns out it
does.
> With `ref` as a `TypeCtor`:
> ```d
> // a function that returns a function ptr that returns an int
> by ref
> ref(int) function(int) makesFPbyRef();
> // function ptr as a parameter type thar returns an int by ref
> void takesFP(ref(int) function() funcPtr)
> // function ptr as a ref parameter type thar returns an int by
> ref
> void takesFP(ref ref(int) function() funcPtr)
> // normal variable type, can be a NOOP or a semantic error
> struct S { ref(int) member; }
> ```
>
> That being said, I understand that your proposal is not only
> about the ref issue but to make the grammar for `Type` nicer.
It has `ref` as its main motivation.
First, there’s a difference between making `ref` a `TypeCtor` and
making it a type constructor. The first is grammar/syntax-only
and the other is a semantic language construct. I’ll assume you
mean both; listing it as a `TypeCtor` without actually following
up semantically would definitely be possible, but very confusing.
I’m proposing a grammar change that is mere addition. The
deprecations I suggested are entirely optional and not required
to make the syntax work. Also, I’m proposing a grammar change, no
semantics change.
Looking at `struct S { ref(int) member; }`, it really seems you
propose that `ref` be a full-fledged type constructor: Look no
further than C++ – they have a reference type constructor and in
C++, essential (core!) language and library constructs don’t work
with references: Pointer to a reference and (as a logical
consequence) an array of references are not well-formed as a
type. A non-compositional type system is the last thing D needs.
I’ve thought long about this. **`ref(`***`Type`***`)`** as a
syntax construct doesn’t get you far.
```d
void takesFP(ref ref(int) function() funcPtr)
```
This is akin to member functions written like this:
```d
const const(int) f() { … }
```
It’s not a nice read.
---
> Then, what is following will be a bit off-topic but, I'd like
> to bring the fact that it might be desirable to keep parens for
> builtin tuples, although it's been a while that the topic was
> not discussed here. In particular a `TypeTuple` made of a
> single `Type` would be hard to express properly.
This is no issue at all. With parentheses for tuple syntax, the
1-tuple for *values* must be expressed as `(value,)` because
`(value)` is a plain expression, so it would just be consistent
to require the trailing comma with *types* as well: `(int)` is
`int`, but `(int,)` is a 1-tuple with an `int` component.
For the record: I’ve objected to parentheses for tuples from the
beginning. Parentheses are for grouping, not for constructing. My
take on the tuples front was to look at static arrays as the
special case of tuples that are homogeneous (the same type
iterated), and generalize them for heterogeneous components:
`int[2]` is a shorthand for `[int, int]`; and `[int, string]` is
a heterogeneous tuple. You build such a tuple like you build an
array: `[1, "abc"]`. Indexing with a run-time index is supported
by Design by Introspection: A `[int, immutable int]` can give you
`ref const(int)` access, a `[int, long]` can give you `long`
access by value, but no `ref` access.
More information about the Digitalmars-d
mailing list