May 10, 2023
On 5/10/23 10:45 AM, Walter Bright wrote:
> On 5/7/2023 10:56 AM, David Gileadi wrote:
>> On 5/6/23 5:50 PM, Walter Bright wrote:
>> If you happen to be using Thunderbird, I made an add-on that renders Markdown messages pretty well.
>>
>> https://addons.thunderbird.net/en-US/thunderbird/addon/render-markdown-messages/?src=search
> 
> I actually found and installed that last night! Thanks, it works great!

You're welcome!
May 11, 2023
On 08.05.23 13:21, Petar Kirov [ZombineDev] wrote:
> On Sunday, 7 May 2023 at 07:35:22 UTC, Timon Gehr wrote:
>> [..]
>>
>> Having `T[2]` be a tuple type `[T,T]` is one of those things that initially sound good enough on paper until you actually examine the existing array semantics that D already has and try to square them with tuple semantics. It does not work at all. D would need to break arrays. It's a pipe dream.
>>
> 
> Can you explain in more detail which parts of the language make the unification impossible currently? Or to phrase the question differently, in a hypothetical D3 language what (breaking) changes we would need to do relative to D2 to make this possible?

I am not sure it is desirable if arrays are not all value types.

- If sliced, `T[n]` results in a `T[]`. Tuple slices should not decay into by-reference array slices randomly based on whether element types match. Also affects array assignment syntax and array operations.

- Type of array literals is `T[]` (uniform element type, dynamic length, reference type). It makes very little sense to have this and also have `[int, string]` be a tuple type.

- Tuple indices (presumably should) need to be statically known, array indices do not. Having `[T,S] t; e=t[i]` evaluate `i` at compile time iff `!is(T==S)` is potentially surprising behavior.

- `T[n]` has properties like `.ptr`, `dup`, `idup`. It seems a bit weird to provide this for tuples and it's not clear what they should do. I guess enabling them conditionally is an option, but that seems wacky.

- `void[n]` and `void[]`. How do they fit into the tuple story?
May 11, 2023

On Thursday, 11 May 2023 at 11:38:08 UTC, Timon Gehr wrote:

>

On 08.05.23 13:21, Petar Kirov [ZombineDev] wrote:

>

On Sunday, 7 May 2023 at 07:35:22 UTC, Timon Gehr wrote:

>

[..]

Having T[2] be a tuple type [T,T] is one of those things that initially sound good enough on paper until you actually examine the existing array semantics that D already has and try to square them with tuple semantics. It does not work at all. D would need to break arrays. It's a pipe dream.

Can you explain in more detail which parts of the language make the unification impossible currently? Or to phrase the question differently, in a hypothetical D3 language what (breaking) changes we would need to do relative to D2 to make this possible?

I am not sure it is desirable if arrays are not all value types.

[snip]

Good points. I'll add:

  • sizeof(T[0]) == 0, but sizeof(Tuple!()) == 1. I'm not sure why.
May 11, 2023

On Thursday, 11 May 2023 at 13:51:28 UTC, Dukc wrote:

>

Good points. I'll add:

  • sizeof(T[0]) == 0, but sizeof(Tuple!()) == 1. I'm not sure why.

That sounds correct because tuples are structs with array semantics. Empty struct size is one, so should be the size of an empty tuple.

May 12, 2023

This is 100% off-topic now. This should be in its separate thread.

On Thursday, 11 May 2023 at 11:38:08 UTC, Timon Gehr wrote:

>

On 08.05.23 13:21, Petar Kirov [ZombineDev] wrote:

>

On Sunday, 7 May 2023 at 07:35:22 UTC, Timon Gehr wrote:

>

[..]

Having T[2] be a tuple type [T,T] is one of those things that initially sound good enough on paper until you actually examine the existing array semantics that D already has and try to square them with tuple semantics. It does not work at all. D would need to break arrays. It's a pipe dream.

Can you explain in more detail which parts of the language make the unification impossible currently? Or to phrase the question differently, in a hypothetical D3 language what (breaking) changes we would need to do relative to D2 to make this possible?

I am not sure it is desirable if arrays are not all value types.

  • If sliced, T[n] results in a T[]. Tuple slices should not decay into by-reference array slices randomly based on whether element types match. Also affects array assignment syntax and array operations.

There’s two kinds of slices: xs[] and xs[i .. j].

The first one should always return a slice type, i.e. T[] for some T.

Of course, you can’t slice a heterogeneous tuple like. You can’t slice it with run-time indices either. With indices known at compile-time, the result can be a tuple, but it won’t be, unless specifically asked to. It generally would become a slice, like for arrays:

int[5] xs;
auto   ys = xs[2..4]; // typeof(ys) == int[]
int[2] zs = xs[2..4]; // You get int[2] if you ask for it.

If you change the type of xs to Tuple!(long, int, int, int, int) all of that should still work, but if you also replace e.g. 2 with a run-time variable, it would not work anymore.

>
  • Type of array literals is T[] (uniform element type, dynamic length, reference type). It makes very little sense to have this and also have [int, string] be a tuple type.

The actual type of a “braced literal” (let’s call it that) is neither T[] nor T[n]. It’s something internal to the compiler, something the D grammar has no syntax for.

It obviously isn’t T[n] because if you ask a T[n] its type, it answers T[n].
It is not a T[] wither because – even though if you ask its type it answers T[] – it can do things a T[] generally can’t do: It can be converted to a T[n] if requested to, it even infers n; a general T[] can’t do that.

“The type of braced literals” is a type of its own.

Why couldn’t a “braced literal” be extended so that it converts to a tuple if asked to? The only new thing would be that there would be literals that you can’t initialize an auto variable with, but you can initialize a variable with it if its type is a tuple. That is because auto never infers static array types and likewise never infers tuple types, thus auto requires them to become a slice and they would need a common type for that. If there is none it’s a compile-error.

The same way we have staticArray that makes literals become a static array type, we can have asTuple that makes literals become tuple types:

auto xs = [1, 2.0];             // typeof(xs) == double[]
auto ys = [1, 2.0].staticArray; // typeof(ys) == double[2]
auto zs = [1, 2.0].asTuple;     // typeof(zs) == [int, double]

auto bad = [new Object, 1]; // no common type for T[] of Object and int.
[Object, int] good1 = [new Object, 1]; // no type inference → no common type needed
auto good2 = [new Object, 1].asTuple; // typeof(good2) == typeof(good1)

Its implementation would be really simple:

auto asTuple(Ts...)([Ts...] tuple) => tuple;
// staticArray for comparison:
auto staticArray(T, size_t n)(T[n] array) => array;
>
  • Tuple indices (presumably should) need to be statically known, array indices do not. Having [T, S] t; e = t[i] evaluate i at compile time iff !is(T == S) is potentially surprising behavior.

It sounds weird, but there is a kind of spectrum between truly heterogeneous tuples and arrays. There’s tuples with varying degrees of homogeneity.

“Tuple indices need to be statically known” Yes, if the tuple is something like Object and int because they are totally unrelated. (It could be a sum type, though.) A tuple of int and long is kind of in-between and a tuple of int and immutable int is as close to an array as it could be without actually being one.

I’d phrase it the other way around: Every tuple supports indexing if the index is known at compile-time, and – for the record – that indexing is always by reference. A tuple would conditionally support run-time indexing depending on how similar its types are. Run-time indexing can be by reference or by value, again depending on how similar its types are. A static array viewed as a tuple of repeated type just so happens to satisfy the conditions such that run-time indexing by reference is always possible. Some non-array tuples allow for run-time indexing by reference as well. It’s simple Design by Introspection:

  • If the types have a common reference type (e.g. int and immutable(int) can be referenced as const(int)), run-time indexing returns const(int) by reference.
  • If the types have a common type (e.g. int and long), run-time indexing returns long by value.

The neat things is that if you expected run-time indexing behavior, but the index is available at compile-time, you might get a different type, but a type that’s better than the one you asked for.
If you expected indexing by value and it happens to be indexing by reference, the value is probably still copied; the exception is auto ref.

On the off-chance that you really needed a very specific behavior, you can ensure to get it. The simple syntax will give you the best it can given the circumstances, i.e. the types of the tuple and the compile-time-ness of the index.

>
  • T[n] has properties like .ptr, dup, idup. It seems a bit weird to provide this for tuples and it's not clear what they should do. I guess enabling them conditionally is an option, but that seems wacky.

You generally don’t provide them for tuples. They would have those properties, if the types allow it. It’s just Design by Introspection. I’d not call that wacky.

>
  • void[n] and void[]. How do they fit into the tuple story?

My suggestion would be: T[n] is a shorthand for [T, T, ...] repeated n times, unless T is void or n is 0. In those cases, T[n] is its own type. The first one is because a void[n] doesn’t store n values of type void, it’s untyped memory of n bytes; you can slice it, but not index it. The second one is because T[0] has an associated type. I can ask a Tuple!(int, int) “Are the types of your elements the same type and if so, what is that type?” and get the answer: Yes, int. If I ask Tuple!(int, long), the answer is no. If I ask Tuple!(), the answer is yes, but there is no type!

We’d therefore have T[0] separate from the type of the empty tuple, at least if T is not void. I guess we can make void[0] the empty tuple type.

void[] is unrelated, it’s a slice, not an array or tuple.

May 12, 2023

On Thursday, 11 May 2023 at 13:51:28 UTC, Dukc wrote:

>

sizeof(Tuple!()) == 1. I'm not sure why.

The spec says sizeof for an empty struct is implementation defined:
https://dlang.org/spec/struct.html#struct_layout

May 12, 2023
It also says:

> 2. Structs with no fields of non-zero size (aka *Empty Structs*) have a
size of one byte.

On Fri, May 12, 2023, 7:01 PM Nick Treleaven via Digitalmars-d < digitalmars-d@puremagic.com> wrote:

> On Thursday, 11 May 2023 at 13:51:28 UTC, Dukc wrote:
> > `sizeof(Tuple!()) == 1`. I'm not sure why.
>
> The spec says `sizeof` for an empty struct is implementation
> defined:
> https://dlang.org/spec/struct.html#struct_layout
>


May 13, 2023

On Thursday, 11 May 2023 at 13:51:28 UTC, Dukc wrote:

>

sizeof(Tuple!()) == 1. I'm not sure why.

A misfeature copied from C++ ("two instances of an empty class must have different addresses"). There are workarounds, such as like making the struct 'extern(C)', but they are ugly and unreliable.

May 13, 2023

On Saturday, 13 May 2023 at 04:16:12 UTC, Max Samukha wrote:

>

such as like

I dream of a utopian future, in which humanity will find ways to edit forum posts.

May 13, 2023

On Monday, 8 May 2023 at 17:02:07 UTC, Quirin Schroll wrote:

>

The proposal can be summed up as:

  1. Allow TypeCtor in the TypeCtor(Type) of BasicType syntax to be “mutable,” which is syntactically just nothing, i.e. allow BasicType to be (Type).
  2. Allow ref as the initial token for a type; such a type must be a function or delegate type to make sense.

They’re even orthogonal: The first clearly does not depend on the second and even the second does not depend on the first, but they really shine together.

Just noticed we have this form for function literals:

function RefOrAutoRefopt Typeopt ParameterWithAttributesopt FunctionLiteralBody2

https://dlang.org/spec/expression.html#function_literals

But for function types we have just:

 TypeCtorsopt BasicType function Parameters FunctionAttributesopt

https://dlang.org/spec/type.html (inlining the TypeSuffix form)

It seems we could add this form to Type for consistency with function literals:

function RefOrAutoRefopt Type ParameterWithAttributes

So this works:
void f(function ref int() g);

And add a similar type for delegates:

delegate RefOrAutoRefopt Type ParameterWithMemberAttributes

That would be a smaller impact change than parenthesized types.