May 08, 2023

On Saturday, 6 May 2023 at 23:28:58 UTC, max haughton wrote:

>

On Saturday, 6 May 2023 at 20:02:30 UTC, ryuukk_ wrote:

>

[...]

This wouldn't be that hard to do but then you have a tradeoff between making this cleaner and making other contexts more confusing.

On the compiler side it would be interesting to make it output some kind of prose based on some kind of type pattern matching / unification e.g. rather than saying "Cannot call X with Y", we'd have a much more contextual error message that uses the information in the template signature (e.g. for (K, V)(inout(V[K]) to be matched, it must satisfy the pattern, so must be an AA of type V[K]).

There's a dlang/projects entry for error messages, this would make a good thing to be done in that project.

As for the runtime, I'm not a big fan of these free functions either.

Yes, I think that get should not be directly callable but rather the compiler should insert a call to it. That way you can call it something else in druntime (__getAAKey or somrthing like that) and the compiler can lower to it in case the lhs of the dot expression is an associative array. It adds a bit of complexity in the compiler, but it gets rid of these weird error messages.

May 08, 2023

On Sunday, 7 May 2023 at 14:19:49 UTC, Steven Schveighoffer wrote:

>

[..]

I completely agree about you in the general case. However, just like you highlighted the interaction between std.conv.to and core.time.to, I believe we do have something we can do to improve the status quo in this specific case, although not easily feasible in the current language - if the compiler lowered V[K] types to a fully library defined type (say core.associative_array.Hash(Key, Value)), then all the AA-related free functions we currently have in object.d would become member functions and then the compiler wouldn't consider them as overload candidates.

Speaking of this, I now remembered that you created this project: https://github.com/schveiguy/newaa

What language changes are necessary before we can replace the built-in AAs with a completely library-based solution?

May 08, 2023

On 5/7/23 11:31 PM, ryuukk_ wrote:

>

You don't understand, my complain isn't about UFCS, it's about the error message that is misleading when trying to debug a problem in your project, the compiler never gives you the hint that Something doesn't have a get function, it tells you that in some other places it doesn't match any overload, it's perhaps time saved when you were looking to use an UFCS function, but it is time wasted when you were looking to call a function from Something

I take the "no overloads match for function in unrelated module" to mean the function doesn't exist as a method. If there was even one get method, then it would not even look for other functions.

This is somewhat par for the course in languages that have overload resolution. It found something by that name, but couldn't make it work. The unique part about D is that those functions can be outside the type even though they look like they are method calls.

>

I perhaps expect the following error message:

onlineapp.d(6): Error: no property `get` for `test` of type `Something`
onlineapp.d(6): Note: The following UFCS functions where found:

/dlang/dmd/linux/bin64/../../src/druntime/import/object.d(3442):
         `get(K, V)(inout(V[K]) aa, K key, lazy inout(V) defaultValue)`
/dlang/dmd/linux/bin64/../../src/druntime/import/object.d(3449):
         `get(K, V)(inout(V[K])* aa, K key, lazy inout(V) defaultValue)`

onlineapp.d(6): Error: none of the overloads of template `object.get` are callable using argument types `!()(Something)`

Once you get used to UFCS, you will understand these error messages easier.

But the compiler can always use clearer error messages.

>

If your language has good feature, diagnostics should match, otherwise it's like with this global that can't be debugged, you perhaps learned to live with it, i haven't and refuse to do so

Not being able to debug the global is an actual bug though, not a language design feature.

My comment on it was that I don't really use debuggers, even for other languages. I didn't "learn to live with it", I just never needed it.

-Steve

May 08, 2023

On 5/8/23 5:53 AM, Petar Kirov [ZombineDev] wrote:

>

On Sunday, 7 May 2023 at 14:19:49 UTC, Steven Schveighoffer wrote:

>

[..]

I completely agree about you in the general case. However, just like you highlighted the interaction between std.conv.to and core.time.to, I believe we do have something we can do to improve the status quo in this specific case, although not easily feasible in the current language - if the compiler lowered V[K] types to a fully library defined type (say core.associative_array.Hash(Key, Value)), then all the AA-related free functions we currently have in object.d would become member functions and then the compiler wouldn't consider them as overload candidates.

That possibly could improve the situation. UFCS "properties" for AAs are kinda sucky.

But that still leaves normal array properties, like .dup. I don't see us ever changing slices to templated structs.

>

Speaking of this, I now remembered that you created this project: https://github.com/schveiguy/newaa

What language changes are necessary before we can replace the built-in AAs with a completely library-based solution?

Two problems. One is straightforward, but requires some language updates: Having some mechanism to tell opIndex that the result should be inserted if it doesn't exist. Used in cases like:

int[int][int] aa;

++aa[42][24]; // currently compiles

The second is not as straightforward. There are a few implicit casts that have no analog for structs. Without some way to say e.g. Foo!(T) can be casted implicitly to Foo!(const(T)), I don't know how we can figure that one.

Aside from that, there are a lot of things that can be done to newaa that will bring it closer to usable. I just haven't done them yet.

The biggest use case right now is building an AA at compile time, and using it at runtime.

-Steve

May 08, 2023

On Monday, 8 May 2023 at 16:08:32 UTC, Steven Schveighoffer wrote:

>

[..]

That possibly could improve the situation. UFCS "properties" for AAs are kinda sucky.

But that still leaves normal array properties, like .dup. I don't see us ever changing slices to templated structs.

Hmm, that doesn't sound like the worst idea. From implementation point of view, we much be extra careful to avoid any sort of pessimization (e.g. template code bloat), since slices are used everywhere, but other than that, why not?

In some languages, even built-in integer types are "library-defined", see e.g.:

Swift:

Anyway, let's not get ahead of ourselves.

> >

Speaking of this, I now remembered that you created this project: https://github.com/schveiguy/newaa

What language changes are necessary before we can replace the built-in AAs with a completely library-based solution?

Two problems. One is straightforward, but requires some language updates: Having some mechanism to tell opIndex that the result should be inserted if it doesn't exist. Used in cases like:

int[int][int] aa;

++aa[42][24]; // currently compiles

Yeah, the so-called autovivification. For a moment I was confused as to what's the problem with simply:

  1. Having opIndex return by ref, so you can mutate the value in-place.
  2. Having opIndex construct the value on first access, something along the lines of:
    if (key !in impl) return impl.at(key).emplace!Value();

But then I remembered that aa[missingKey] actually throws a RangeError and we wouldn't be able to replicate the behaviour if we did 2.

I wonder if the compiler simply could lower:

int[int][int] aa;
++aa[42][24];

to:

int[int][int] aa;
++aa.require(42).require(24);

Would that address this issue?

>

The second is not as straightforward. There are a few implicit casts that have no analog for structs. Without some way to say e.g. Foo!(T) can be casted implicitly to Foo!(const(T)), I don't know how we can figure that one.

Thanks for reminding me, I think this was discussed many times in the past, IIRC it was most recently brought up by deadalnix in the sumtypes thread.

If we consider this issue unsolvable for the time being, a pragmatic way forward would be to consider the following:
The compiler already special cases T[] and V[K] types with regards to type qualifiers. Perhaps we can keep this code around and update it to work with the new AA implementation. That would mean that the implicit type qualifier conversion won't work if one directly imports the AA type: core.associative_array.Hash!(K, V), however existing code that uses the V[K] syntax would continue working fine.

>

Aside from that, there are a lot of things that can be done to newaa that will bring it closer to usable. I just haven't done them yet.

The biggest use case right now is building an AA at compile time, and using it at runtime.

Nevertheless, I think you have very solid progress so far! Hopefully, it won't be too long before we incorporate it in some form in Druntime!

May 08, 2023

On 5/8/23 6:12 PM, Petar Kirov [ZombineDev] wrote:

>

On Monday, 8 May 2023 at 16:08:32 UTC, Steven Schveighoffer wrote:

>

[..]

That possibly could improve the situation. UFCS "properties" for AAs are kinda sucky.

But that still leaves normal array properties, like .dup. I don't see us ever changing slices to templated structs.

Hmm, that doesn't sound like the worst idea. From implementation point of view, we much be extra careful to avoid any sort of pessimization (e.g. template code bloat), since slices are used everywhere, but other than that, why not?

In some languages, even built-in integer types are "library-defined", see e.g.:

Swift:

Anyway, let's not get ahead of ourselves.]

Yeah, not touching that ;) To be frank, I've used swift's different integer types, and it sucks compared to D.

> > >

Speaking of this, I now remembered that you created this project: https://github.com/schveiguy/newaa

What language changes are necessary before we can replace the built-in AAs with a completely library-based solution?

Two problems. One is straightforward, but requires some language updates: Having some mechanism to tell opIndex that the result should be inserted if it doesn't exist. Used in cases like:

int[int][int] aa;

++aa[42][24]; // currently compiles

Yeah, the so-called autovivification. For a moment I was confused as to what's the problem with simply:

  1. Having opIndex return by ref, so you can mutate the value in-place.
  2. Having opIndex construct the value on first access, something along the lines of:
      if (key !in impl) return impl.at(key).emplace!Value();

But then I remembered that aa[missingKey] actually throws a RangeError and we wouldn't be able to replicate the behaviour if we did 2.

I wonder if the compiler simply could lower:

int[int][int] aa;
++aa[42][24];

to:

int[int][int] aa;
++aa.require(42).require(24);

Would that address this issue?

What is needed is to have the compiler try a different hook when this is expected. This is actually exactly what the compiler does for AAs -- a different runtime call is used when the result of the opIndex is expected to be filled in if absent.

I would not use require, but rather, another opIndex flavor. This shouldn't be tuned specifically to AA, we should do it right for all custom aggregates.

> >

The second is not as straightforward. There are a few implicit casts that have no analog for structs. Without some way to say e.g. Foo!(T) can be casted implicitly to Foo!(const(T)), I don't know how we can figure that one.

Thanks for reminding me, I think this was discussed many times in the past, IIRC it was most recently brought up by deadalnix in the sumtypes thread.

If we consider this issue unsolvable for the time being, a pragmatic way forward would be to consider the following:
The compiler already special cases T[] and V[K] types with regards to type qualifiers. Perhaps we can keep this code around and update it to work with the new AA implementation. That would mean that the implicit type qualifier conversion won't work if one directly imports the AA type: core.associative_array.Hash!(K, V), however existing code that uses the V[K] syntax would continue working fine.

No, if we fix it, we should fix it once and for all. I don't think making AA into a library type is the only goal. The more D can allow people to write library types that mimic the builtins, the better off we will be.

> >

Aside from that, there are a lot of things that can be done to newaa that will bring it closer to usable. I just haven't done them yet.

The biggest use case right now is building an AA at compile time, and using it at runtime.

Nevertheless, I think you have very solid progress so far! Hopefully, it won't be too long before we incorporate it in some form in Druntime!

Thanks! I think it's all pretty straightforward stuff -- implementing all the various AA things (like require, etc.), and being able to print the thing properly.

-Steve

May 08, 2023
On Mon, May 08, 2023 at 10:12:53PM +0000, Petar via Digitalmars-d wrote: [...]
> > Two problems. One is straightforward, but requires some language
> > updates: Having some mechanism to tell `opIndex` that the result
> > should be inserted if it doesn't exist. Used in cases like:
> > ```d
> > int[int][int] aa;
> > 
> > ++aa[42][24]; // currently compiles
> > ```
> 
> On Monday, 8 May 2023 at 16:08:32 UTC, Steven Schveighoffer wrote:
> Yeah, the so-called
> [autovivification](https://en.wikipedia.org/wiki/Autovivification).
> For a moment I was confused as to what's the problem with simply:
> 1. Having `opIndex` return by `ref`, so you can mutate the value
> in-place.
> 2. Having `opIndex` construct the value on first access, something
> along the lines of:
>   `if (key !in impl) return impl.at(key).emplace!Value();`
> 
> But then I remembered that `aa[missingKey]` actually throws a `RangeError` and we wouldn't be able to replicate the behaviour if we did 2.

Sigh: https://issues.dlang.org/show_bug.cgi?id=7753


T

-- 
Democracy: The triumph of popularity over principle. -- C.Bond
May 09, 2023

On Monday, 8 May 2023 at 03:31:10 UTC, ryuukk_ wrote:

>

I perhaps expect the following error message:

onlineapp.d(6): Error: no property `get` for `test` of type `Something`
onlineapp.d(6): Note: The following UFCS functions where found:

https://github.com/dlang/dmd/pull/15208

May 09, 2023

On Tuesday, 9 May 2023 at 09:37:37 UTC, Dennis wrote:

>

On Monday, 8 May 2023 at 03:31:10 UTC, ryuukk_ wrote:

>

I perhaps expect the following error message:

onlineapp.d(6): Error: no property `get` for `test` of type `Something`
onlineapp.d(6): Note: The following UFCS functions where found:

https://github.com/dlang/dmd/pull/15208

Thanks a lot!

1 2
Next ›   Last »