Jump to page: 1 2
Thread overview
August 15
I just wanted to share a brief discussion on a PR last night, because it's something that's always bugged me, and there is a change in 2.111 that tightens the rules for declaring auto ref such that the keywords must appear next to eachother.

In the PR there was a piece of code that went `const auto ref T`, and I suggested changing to `auto ref const T` as convention at least.

The reason I perceive is that this is valid syntax: auto ref
const(CowArray) rhs
This is not: const(auto ref CowArray) nhs

For me, it's a conceptual flow thing:
const auto ref T goes: type stuff (const) -> storage class stuff (auto ref)
-> type stuff (T)
auto ref const T goes: storage class stuff (auto ref) -> type stuff (const T
)

It feels crude to interleave type stuff and storage class stuff in an arbitrary way.

The distinction feels more compelling when you consider that parens may appear after type constructors (const(T)), and so in those cases, the code MUST be written with the const immediately preceding the type, forcing the storage class to the left.

Since it's invalid to put storage class stuff on the end (actual type must be on the end), then I would mandate that storage class stuff should go at the start, not randomly in the middle somewhere, ie: storage_class type_constructor actual_type

If it were up to me, I would mandate this in the spec, but failing that, at least proliferate this by general policy; I think this helps non-D coders to osmose this complexity without a detailed conversation... and for everyone else, the code just reads more consistently.

I see a surprising number of people writing `const ref T`, and I suspect that people are writing it holding the same kind of conceptual confusion that a lot of new users have expressed to me. As I see it, the fact people tend to write this at all is clear evidence that we shouldn't allow it!


Similarly, allowing attributes on functions should likewise appear after the function prototype:

struct S {
  const(T) method();
  const T method(); // not the same; synonym for `T method() const`
}

This kind of confusion is just totally unnecessary. Any non-expert reader would assume they are the same. There's no value in inviting this confusion.


August 15
On Thursday, 15 August 2024 at 00:35:33 UTC, Manu wrote:
> For me, it's a conceptual flow thing:
> const auto ref T goes: type stuff (const) -> storage class stuff (auto ref)
> -> type stuff (T)
> auto ref const T goes: storage class stuff (auto ref) -> type stuff (const T
> )
>
> It feels crude to interleave type stuff and storage class stuff in an arbitrary way.
>
> The distinction feels more compelling when you consider that parens may appear after type constructors (const(T)), and so in those cases, the code MUST be written with the const immediately preceding the type, forcing the storage class to the left.

I guess the most consistent thing would be to always use the parentheses, and write `ref const(T)`.

> Similarly, allowing attributes on functions should likewise appear after the function prototype:
>
> struct S {
>   const(T) method();
>   const T method(); // not the same; synonym for `T method() const`
> }

My rule is that attributes that apply to `this` go on the right, and attributes that apply to the entire function go on the left. So:

    @safe nothrow T method() const;

    // Or on multiple lines:
    @safe nothrow
    T method() const;
August 15

On Thursday, 15 August 2024 at 00:35:33 UTC, Manu wrote:

>

The reason I perceive is that this is valid syntax: auto ref
const(CowArray) rhs
This is not: const(auto ref CowArray) nhs

For me, it's a conceptual flow thing:
const auto ref T goes: type stuff (const) -> storage class stuff (auto ref)
-> type stuff (T)
auto ref const T goes: storage class stuff (auto ref) -> type stuff (const T
)

It feels crude to interleave type stuff and storage class stuff in an arbitrary way.

The distinction feels more compelling when you consider that parens may appear after type constructors (const(T)), and so in those cases, the code MUST be written with the const immediately preceding the type, forcing the storage class to the left.

Since it's invalid to put storage class stuff on the end (actual type must be on the end), then I would mandate that storage class stuff should go at the start, not randomly in the middle somewhere, ie: storage_class type_constructor actual_type

If it were up to me, I would mandate this in the spec, but failing that, at least proliferate this by general policy; I think this helps non-D coders to osmose this complexity without a detailed conversation... and for everyone else, the code just reads more consistently.

I see a surprising number of people writing const ref T, and I suspect that people are writing it holding the same kind of conceptual confusion that a lot of new users have expressed to me. As I see it, the fact people tend to write this at all is clear evidence that we shouldn't allow it!

Yeah, I feel you. When I first started writing in D I’d also use const ref, but I agree that interleaving the storage class and the type is not right. I’m not alone in having started with const ref, and then having moved to using ref const as I understood the language better.
I think part of the reason some gravitate to const ref because of ignorance when coming from C++, but I never used C++ because I was aware of its reputation. Instead, I found the ordering to violate English adjective ordering. ref const T sounds wrong in the same way as ‘red big balloon’. In English you can have a ‘constant reference integer’ but not a ‘reference constant integer’; it sounds like an imperative instruction.

August 15
On 15/08/2024 9:05 PM, IchorDev wrote:
> Yeah, I feel you. When I first started writing in D I’d also use `const ref`, but I agree that interleaving the storage class and the type is not right. I’m not alone in having started with `const ref`, and then having moved to using `ref const` as I understood the language better.
> I think part of the reason some gravitate to `const ref` because of ignorance when coming from C++, but I never used C++ because I was aware of its reputation. Instead, I found the ordering to violate English adjective ordering. `ref const T` sounds wrong in the same way as ‘red big balloon’. In English you can have a ‘constant reference integer’ but not a ‘reference constant integer’; it sounds like an imperative instruction.

+1

Perhaps not an error in practice, but a warning is certainly warranted as it shows a lack of understanding in the language.
August 15

On Thursday, 15 August 2024 at 09:05:02 UTC, IchorDev wrote:

>

Yeah, I feel you. When I first started writing in D I’d also use const ref [...] I found the ordering to violate English adjective ordering. ref const T sounds wrong in the same way as ‘red big balloon’.

Yeah. As long as the language allows both, I would always go with the version that sounds more like proper english.
But if we do a restriction at all, I would require to always put const at the end (e.g. 'ref T const') to keep it consistent for functions and values.

August 15
On Thursday, August 15, 2024 4:34:49 AM MDT Richard (Rikki) Andrew Cattermole via Digitalmars-d wrote:
> On 15/08/2024 9:05 PM, IchorDev wrote:
> > Yeah, I feel you. When I first started writing in D I’d also use `const
> > ref`, but I agree that interleaving the storage class and the type is
> > not right. I’m not alone in having started with `const ref`, and then
> > having moved to using `ref const` as I understood the language better.
> > I think part of the reason some gravitate to `const ref` because of
> > ignorance when coming from C++, but I never used C++ because I was aware
> > of its reputation. Instead, I found the ordering to violate English
> > adjective ordering. `ref const T` sounds wrong in the same way as ‘red
> > big balloon’. In English you can have a ‘constant reference integer’ but
> > not a ‘reference constant integer’; it sounds like an imperative
> > instruction.
>
> +1
>
> Perhaps not an error in practice, but a warning is certainly warranted as it shows a lack of understanding in the language.

Not really. Unless you actually need to use parens, const ref is perfectly valid, and I really don't see the problem. I understand const perfectly fine and yet I always use const ref unless I have to use ref const, because ref const is just plain ugly - and it doesn't add any value except in cases where you can't use it anyway.

I agree that having function attributes be legal on both the left-hand and right-hand side of a function is problematic, but I see no value in forcing their order, and in general, making their order matter is just going to be annoying to deal with.

Either way, warnings are a terrible idea in general. When you're dealing with warnings, you end up in one of two situations:

1. You ignore the ones that don't actually need fixing, in which case, the number of warnings will eventually grow to the point that you can't actually see the ones that matter, making the warnings borderline useless.

2. You "fix" all of the warnings so that none are buried, meaning that you're effectively treating all warnings as errors even though many of them don't actually indicate a real problem, making the difference between warnings and errors effectively pointless.

The fact that dmd even has warnings was a huge mistake IMHO. Either they should be errors, or they should be left up to linters, and we should avoid adding new warnings like the plague (honestly, I think that we should really consider getting rid of them entirely).

And warnings in D are even worse than they are in most languages, because -w is unfortunately a thing, meaning that adding a warning can result in an error, which can not only make perfectly valid code cease to compile with a compiler update, but it affects conditional compilation, because it affects checks for whether a particular piece of code compiles, which is used _heavily_ in templated code. So, you can end up with template constraints which suddenly fail - or even worse, the code ends up compiling but using a different branch, and you silently end up with worse performance (or maybe even altered behavior in some cases).

If you want to have a linter of some kind warn about random stuff like const ref, then I really don't care, but adding anything of the sort to the compiler is a terrible idea.

- Jonathan M Davis




August 15
On Thu, 15 Aug 2024 at 21:05, Jonathan M Davis via Digitalmars-d < digitalmars-d@puremagic.com> wrote:

> On Thursday, August 15, 2024 4:34:49 AM MDT Richard (Rikki) Andrew
> Cattermole
> via Digitalmars-d wrote:
> > On 15/08/2024 9:05 PM, IchorDev wrote:
> > > Yeah, I feel you. When I first started writing in D I’d also use `const
> > > ref`, but I agree that interleaving the storage class and the type is
> > > not right. I’m not alone in having started with `const ref`, and then
> > > having moved to using `ref const` as I understood the language better.
> > > I think part of the reason some gravitate to `const ref` because of
> > > ignorance when coming from C++, but I never used C++ because I was
> aware
> > > of its reputation. Instead, I found the ordering to violate English adjective ordering. `ref const T` sounds wrong in the same way as ‘red big balloon’. In English you can have a ‘constant reference integer’
> but
> > > not a ‘reference constant integer’; it sounds like an imperative instruction.
> >
> > +1
> >
> > Perhaps not an error in practice, but a warning is certainly warranted as it shows a lack of understanding in the language.
>
> Not really. Unless you actually need to use parens, const ref is perfectly valid, and I really don't see the problem.


Really? I just explained it... you weren't even mildly persuaded?

I understand const perfectly fine
> and yet I always use const ref unless I have to use ref const, because ref const is just plain ugly -


Subjective; and I feel the opposite way. However there is definitely one that is *more correct*, and it's undeniably the way I argue here.

and it doesn't add any value except in cases
> where you can't use it anyway.
>

I reckon there's immense value in representing the language in such a way that you can learn and feel the semantics by osmosis. `storage class` seems to be a complex matter that takes a long time to get a proper feel for even if you do read the spec. I am absolutely convinced that for a majority of newcomers, seeing type declarations separated into distinct parts helps to separate the concepts.

I have had detailed conversations stimulated by this exact confusion on many occasions... writing `const ref` gives people the wrong impression every time and a long detailed conversation necessarily follows, and it's a conversation that's never flattering towards D. In my experience, it's one among a series of small but meaningful-in-aggregate such psychological blows against D whenever I introduce it to new people. It's among a subtle suite of issues that undermine people's confidence that D knows what it's doing very early on.

I agree that having function attributes be legal on both the left-hand and
> right-hand side of a function is problematic, but I see no value in forcing their order, and in general, making their order matter is just going to be annoying to deal with.
>

I see no value in *not *forcing their order. I made my case, apparently you weren't persuaded... make your case, I'd like to hear it. Something like "yeah, I just kinda like to mix it up however I want" is definitely not going to persuade me.

Either way, warnings are a terrible idea in general. When you're dealing
> with warnings, you end up in one of two situations:
>
> 1. You ignore the ones that don't actually need fixing, in which case, the
> number of warnings will eventually grow to the point that you can't
> actually
> see the ones that matter, making the warnings borderline useless.
>
> 2. You "fix" all of the warnings so that none are buried, meaning that you're effectively treating all warnings as errors even though many of them don't actually indicate a real problem, making the difference between warnings and errors effectively pointless.
>
> The fact that dmd even has warnings was a huge mistake IMHO. Either they
> should be errors, or they should be left up to linters, and we should avoid
> adding new warnings like the plague (honestly, I think that we should
> really
> consider getting rid of them entirely).
>
> And warnings in D are even worse than they are in most languages, because
> -w
> is unfortunately a thing, meaning that adding a warning can result in an
> error, which can not only make perfectly valid code cease to compile with a
> compiler update, but it affects conditional compilation, because it affects
> checks for whether a particular piece of code compiles, which is used
> _heavily_ in templated code. So, you can end up with template constraints
> which suddenly fail - or even worse, the code ends up compiling but using a
> different branch, and you silently end up with worse performance (or maybe
> even altered behavior in some cases).
>

Yes, totally agree; definitely not a warning. Either a spec change, or a convention should be established in the major libraries so people see a consistent pattern they will follow in their own code.



> If you want to have a linter of some kind warn about random stuff like
> const
> ref, then I really don't care, but adding anything of the sort to the
> compiler is a terrible idea.
>
> - Jonathan M Davis
>


August 15
On Thursday, August 15, 2024 7:33:51 AM MDT Manu via Digitalmars-d wrote:
> On Thu, 15 Aug 2024 at 21:05, Jonathan M Davis via Digitalmars-d <
> > Not really. Unless you actually need to use parens, const ref is perfectly valid, and I really don't see the problem.
>
> Really? I just explained it... you weren't even mildly persuaded?

No. The attributes in general are independent from one another. Forcing them to be in a particular order is therefore arbitrary, and it forces everyone to learn whatever that arbitrary order is. I see no value in that, and I don't see any problem with the order being arbitrary. It's far less hassle to be able to just write them out and not care one whit about the order when they're independent from one another.

Changes are being made to force auto ref to be in that order, because
auto ref is basically a single attribute that probably should have been a
new attribute rather than combining two existing attributes, but that would
have meant adding a new keyword, so that's not what was done. The same is
not true for const ref or ref const at all. They're independent attributes
being applied.

The reason that allowing function attributes be on the left-hand side is a problem is because then you get confusing inconsistencies like const not applying to the return type, because it doesn't have parens even though parens aren't required anywhere else unless you're applying const to only part of the type. By requiring that the function attributes go on the right-hand side, you solve that problem - and it still doesn't require that the attributes be in a specific order. It just requires that the attributes being applied to the function be one one side, and the attributes being applied to the return type be on the other.

That being said, when it comes to attributes like public and static, which can't apply to the return type, it arguably is better to allow them on the left (particularly since most folks put them there, and they go on the left for all other declarations), so maybe we should only restrict which side function attributes go on if they could apply to the return type. But that then creates inconsistencies where specific function attributes can go on the left whereas others can't, which could also create confusion, which IIRC, is why Walter has never been in favor of the idea. But I don't think that he's ever really seen problems with

    const int foo() {...}

before either even though most everyone is going to read it wrong unless they're very used to that particular quirk of the language.

Either way, I think that allowing const, immutable, or shared on the left-hand side to apply to the function rather than the return type was a mistake. And maybe the solution is to just require parens in those cases, which would be kind of annoying too, but it would catch a bug without being all that onerous.

In any case, the situation with ref const vs const ref is very different from both auto ref and attributes on functions. The order is arbitrary, and unless you're bringing parens into it, the order doesn't need to be defined. I don't recall ever seeing anyone complain about const ref vs ref const before, and I've never seen it as a problem myself. It just seems needlessly strict to me to require that attributes in general be listed in a specific order, and I don't want to have to worry about learning such rules - particularly since I see no value in forcing a particular order. You're free to disagree, and I don't think that it's particularly surprising if neither of us finds the other's arguments particularly compelling. Clearly, you find some kind of value in forcing the order that I do not understand, whereas I see it as purely an unnecessary complication that would be a hassle to deal with.

Either way, the person to convince would be Walter, and based on past discussions of this sort, I doubt that he'll be convinced, but who knows. It can sometimes be quite surprising what he does or doesn't agree with, and it's not like he never changes his mind.

- Jonathan M Davis



August 16
On 16/08/2024 2:47 AM, Jonathan M Davis wrote:
> Either way, the person to convince would be Walter, and based on past
> discussions of this sort, I doubt that he'll be convinced, but who knows. It
> can sometimes be quite surprising what he does or doesn't agree with, and
> it's not like he never changes his mind.

Considering that he allowed the abomination that is return and scope ordering to result in two different attributes, it's worth talking with him about it I'd say!

August 15
On Thursday, August 15, 2024 8:56:29 AM MDT Richard (Rikki) Andrew Cattermole via Digitalmars-d wrote:
> On 16/08/2024 2:47 AM, Jonathan M Davis wrote:
> > Either way, the person to convince would be Walter, and based on past discussions of this sort, I doubt that he'll be convinced, but who knows. It can sometimes be quite surprising what he does or doesn't agree with, and it's not like he never changes his mind.
>
> Considering that he allowed the abomination that is return and scope ordering to result in two different attributes, it's worth talking with him about it I'd say!

That is indeed an abomination, and I'd love to see that fixed (though
honestly, I'd love to see DIP 1000 thrown out entirely), but it's a very
different situation from const ref vs ref const. The problem with
return scope vs scope return is that it not only makes the order matter, but
it makes it so that each order means different things. On the other hand,
requiring ref const would be requiring a fixed order when we have no need to
do so, and both orders are currently fine.

- Jonathan M Davis



« First   ‹ Prev
1 2