Re: DIP 1038--"@mustUse" (formerly "@noDiscard")--Accepted

2022-02-09 Thread Dukc via Digitalmars-d-announce
On Sunday, 6 February 2022 at 15:43:39 UTC, Ola Fosheim Grøstad 
wrote:
3. *The politics of language improvements*: I don't think this 
should be a library type. I think this feature is too important 
for that. To me this smells of let's move the syntax to a 
library to avoid any discussion about breaking changes. Design 
considerations should not become political, we need to get rid 
of politics and focus on principled strategies that makes the 
whole eco system attractive to more developers (the ones we 
don't have).


This is a disrespectful comment. You're implying that your 
opinion is rational and apolitical, disagreeing with it is 
irrational politics. It is true that no decisions are fully 
politics-free, but please don't pretend that you are above all 
others here in that regard.


Re: DIP 1038--"@mustUse" (formerly "@noDiscard")--Accepted

2022-02-09 Thread Guillaume Piolat via Digitalmars-d-announce

On Monday, 7 February 2022 at 19:57:28 UTC, forkit wrote:
First, I'm not 'insisting' on anything. I'm just expressing a 
view.


nodiscard is already used by more programmers that D is likely 
to ever adopt.


Indeed, it's these programmers that D is trying to adopt.

I'm not sure forcing such people to adapt is necessarily the 
right approach.




I'll have to side with forkit there.

In audio software (at the very least) you pay very dearly the 
price of introducing new _words_, because the existing words 
embodies existing meaning and practice that users have 
internalized.


If you call your "Amount" parameter "Dry/wet" instead, then 
misunderstandings will happen for years without ever a chance to 
correct them, because "Dry/wet" means something already in the 
users mind.


If you call your mutex a "synchronizer" then you have to tell 
everyone what is a synchronizer, why it is needed as a concept, 
and so on. Think: "slices" and "dynamic arrays" in D, a 
distinction that is of no use and begets a lot of 
misunderstandings.


Hence some does of of reusing, reduce mental load. Paucity of 
words helps the cast of D explainers.


Re: DIP 1038--"@mustUse" (formerly "@noDiscard")--Accepted

2022-02-09 Thread Guillaume Piolat via Digitalmars-d-announce
On Wednesday, 9 February 2022 at 14:30:30 UTC, Guillaume Piolat 
wrote:


Hence some does of of reusing,


some dose of reuse*


Re: DIP 1038--"@mustUse" (formerly "@noDiscard")--Accepted

2022-02-09 Thread Paul Backus via Digitalmars-d-announce
On Wednesday, 9 February 2022 at 14:30:30 UTC, Guillaume Piolat 
wrote:

On Monday, 7 February 2022 at 19:57:28 UTC, forkit wrote:
First, I'm not 'insisting' on anything. I'm just expressing a 
view.


nodiscard is already used by more programmers that D is likely 
to ever adopt.


Indeed, it's these programmers that D is trying to adopt.

I'm not sure forcing such people to adapt is necessarily the 
right approach.




I'll have to side with forkit there.

In audio software (at the very least) you pay very dearly the 
price of introducing new _words_, because the existing words 
embodies existing meaning and practice that users have 
internalized.


In D, there is no existing word for this, so from that 
perspective both "mustuse" and "nodiscard" are equally valid.


In other languages, there are multiple existing words:

- C++17: [[nodiscard]]
- C (gcc/clang): __attribute__((warn_unused_result))
- Rust: #[must_use]

If you are used to C++, then you will find "nodiscard" natural, 
and "mustuse" will require you to learn a new word. If you are 
used to Rust, then you will find "mustuse" natural, and 
"nodiscard" would have required you to learn a new word.


And, of course, if you are used to Python or Javascript or one of 
the many other languages that has no word for this at all, it 
will make little difference to you either way.


C++ is quite popular, but it is not the only popular language, 
and there are many D programmers who have never used C++ at all, 
let alone C++17 or later. Therefore, it is a mistake to assume 
that all or even most D programmers have already internalized 
"nodiscard", or indeed *any* particular word for this concept.


Re: DIP 1038--"@mustUse" (formerly "@noDiscard")--Accepted

2022-02-09 Thread rikki cattermole via Digitalmars-d-announce



On 10/02/2022 5:21 AM, Paul Backus wrote:

- C (gcc/clang): __attribute__((warn_unused_result))


C23 will also have [[nodiscard]]

Not only will it have that on functions, but also support a string too.

Unfortunately its looking like we have chosen to diverge from C, and 
therefore won't be completely C compatible soon.


Will be exciting as to what kind of bugs crop up because of this!


Re: Added copy constructors to "Programming in D"

2022-02-09 Thread Ali Çehreli via Digitalmars-d-announce

On 2/9/22 02:15, Anonymouse wrote:

On Saturday, 8 January 2022 at 02:07:10 UTC, Ali Çehreli wrote:
2) The other noteworthy change in the book is my now-different stance 
on variables: Now I recommend 'const' over 'immutable' for variables.


I'm curious, could you elaborate a bit on this? I skimmed through the 
page on Immutability but I didn't find anything explaining it.


To make sure we are looking at the same version, the new content has the 
following section:



in parameters

As we will see in the next chapter, in implies const and is more useful 
with the ‑preview=in command line switch. For that reason, I recommend 
in parameters over const parameters.



  http://ddili.org/ders/d.en/const_and_immutable.html

In short, in the past, under the influence of "stronger guarantee" 
clearly sounding better, I was recommending immutable for variables:


  immutable i = 42;

Realizing that I don't do that in my own code, now I recommend const:

  const i = 42;

Further, now that we have -preview=in (thanks to Mathias Lang), I 
recommend 'in' over const for parameters. (Actually, I had always 
recommended 'in' and did use it in some of the examples in the book 
(inconsistently) but I wasn't using it in my own code.)


But the whole thing is complicated. :) So, I asked for and received 
opinions on this thread:


  https://forum.dlang.org/thread/sig2d4$657$1...@digitalmars.com

I don't find the common description helpful:  "immutable provides 
stronger guarantee." That's true and sounds better than mere "strong" 
but it does not help a programmer with deciding on which one to use. 
Rather, I like the following distinction:


- const is a promise

- immutable is a requirement

Now, that helps me decide which one to use when. Let's start with a 
function:


void foo(in A a, immutable B b) {
  // ...
}

There, foo "promises" to not mutate 'a' ('in' implies 'const') and 
"requires" that 'b' is not mutated by any other code.


With that understanding, it is silly to "require" that no other code 
mutates a local variable:


void x() {
  immutable b = B();  // Really? Who can mutate it?
  // ...
}

So, the following is logical (and shorter :) ):

void x() {
  const b = B();
  // ...
}

Now, if I need to pass it to a function that "requires" immutable, of 
course I will have to define it as immutable to satisfy that requirement:


void x() {
  immutable b = B();
  foo(A(), b);
  // ...
}

Aside: One of the confusions is that 'const' would work there as well 
*if* B did not have any indirection. But if it's defined as e.g.


struct B {
  int[] arr;
}

then, x() will not compile with 'const b'.

In summary:

Variables: 'const' by default, 'immutable' as needed (because somebody 
requires it)


Parameters: 'in' by default, 'immutable' if required

That's my view. I think there are others who disagree with parts of it 
and that's why this issue is surprisingly complicated.


Ali


Re: DIP 1038--"@mustUse" (formerly "@noDiscard")--Accepted

2022-02-09 Thread jmh530 via Digitalmars-d-announce

On Wednesday, 9 February 2022 at 16:21:24 UTC, Paul Backus wrote:

[snip]

In D, there is no existing word for this, so from that 
perspective both "mustuse" and "nodiscard" are equally valid.


In other languages, there are multiple existing words:

- C++17: [[nodiscard]]
- C (gcc/clang): __attribute__((warn_unused_result))
- Rust: #[must_use]

If you are used to C++, then you will find "nodiscard" natural, 
and "mustuse" will require you to learn a new word. If you are 
used to Rust, then you will find "mustuse" natural, and 
"nodiscard" would have required you to learn a new word.




But what color should the bike shed be? ;)


Re: DIP 1038--"@mustUse" (formerly "@noDiscard")--Accepted

2022-02-09 Thread Guillaume Piolat via Digitalmars-d-announce

On Wednesday, 9 February 2022 at 16:21:24 UTC, Paul Backus wrote:
C++ is quite popular, but it is not the only popular language, 
and there are many D programmers who have never used C++ at 
all, let alone C++17 or later. Therefore, it is a mistake to 
assume that all or even most D programmers have already 
internalized "nodiscard", or indeed *any* particular word for 
this concept.


There is also the Nim "discard" statement. I wonder why noone 
stole that feature. Feels more natural to me speak about the 
error being avoided, than a vague statement like "must use". 
C++17 is the most used language in the native space, so yes I 
think it takes precedence in the minds of native programmers. 
But, it is a level of bikeshedding I'm not keen on entering.




Re: DIP 1038--"@mustUse" (formerly "@noDiscard")--Accepted

2022-02-09 Thread apz28 via Digitalmars-d-announce

On Wednesday, 9 February 2022 at 16:21:24 UTC, Paul Backus wrote:
On Wednesday, 9 February 2022 at 14:30:30 UTC, Guillaume Piolat 
wrote:

On Monday, 7 February 2022 at 19:57:28 UTC, forkit wrote:
First, I'm not 'insisting' on anything. I'm just expressing a 
view.


nodiscard is already used by more programmers that D is 
likely to ever adopt.


Indeed, it's these programmers that D is trying to adopt.

I'm not sure forcing such people to adapt is necessarily the 
right approach.




I'll have to side with forkit there.

In audio software (at the very least) you pay very dearly the 
price of introducing new _words_, because the existing words 
embodies existing meaning and practice that users have 
internalized.


In D, there is no existing word for this, so from that 
perspective both "mustuse" and "nodiscard" are equally valid.


In other languages, there are multiple existing words:

- C++17: [[nodiscard]]
- C (gcc/clang): __attribute__((warn_unused_result))
- Rust: #[must_use]



C++17: [[nodiscard]] is just a warning; must use another compiler 
flag in order to have same @mustuse in D -> already discrepancy 
in meaning




Re: Added copy constructors to "Programming in D"

2022-02-09 Thread H. S. Teoh via Digitalmars-d-announce
On Wed, Feb 09, 2022 at 10:28:15AM -0800, Ali Çehreli via 
Digitalmars-d-announce wrote:
[...]
> - const is a promise
> 
> - immutable is a requirement
[...]

Strictly speaking, that's not really an accurate description. :-P  A
more accurate description would be:

- const: I cannot modify the data (but someone else might).

- immutable: I cannot modify the data, AND nobody else can either.

The best way I've found to understand the relationship between const,
immutable, and mutable in D is the following "type inheritance" diagram
(analogous to a class inheritance diagram):

  const
 / \
(mutable)   immutable

Const behaves like the "base class" (well, base type, sortof) that
either mutable or immutable can implicitly convert to. Mutable and
immutable, however, are mutually incompatible "derived classes" that
will not implicitly convert to each other. (Of course, the reality is
somewhat more complex than this, but this is a good, simple conceptual
starting point to understanding D's type system.)

Const means whoever holds the reference to the data cannot modify it. So
it's safe to hand them both mutable and immutable data.

Mutable means you are allowed to modify it, so obviously it's illegal to
pass in const or immutable.  Passing mutable to const is OK because the
recipient cannot modify it, even though the caller himself may (since he
holds a mutable reference to it).

Immutable means NOBODY can modify it, not even the caller. I.e.,
*nobody* holds a mutable reference to the data. So you cannot pass
mutable to immutable.  Obviously, it's safe to pass immutable to const
(the callee cannot modify it anyway, so we're OK).  But you cannot pass
const to immutable, because, as stated above, a const reference might be
pointing to mutable data: even though the holder of the reference cannot
himself modify it, it may have come from a mutable reference somewhere
else. Allowing it would break the rule that immutable means *nobody* has
a mutable reference to the data. So that's not allowed.

IOW, "downcasting" in the above "type hierarchy" is not allowed, in
general.

However, there's a special case where mutable does implicitly convert to
mutable: this is if the mutable reference is unique, meaning that it's
the only reference that exists to that data. In such a case, it's OK to
convert that mutable reference to an immutable one, provided the mutable
reference immediately goes out of scope. After that point, nobody holds
a mutable reference to it anymore, so it fits into the definition of
immutable. This happens when a mutable reference is returned from a pure
function:

MyData createData() pure {
MyData result; // N.B.: mutable
return result;
// mutable reference goes out of scope
}

// OK: function is pure and reference to data is unique
immutable MyData data = createData();

The `pure` ensures that createData didn't cheat and store a mutable
reference to the data in some global variable, so the reference to
MyData that it returns is truly unique. So in this case we allow mutable
to implicitly convert to immutable.

There's also another situation where immutable is allowed to implicitly
convert to mutable: this is when the data is a by-value type containing
no indirections. Essentially, we're making a copy of the immutable data,
so it doesn't matter if we modify the copy, since we're not actually
modifying the original data.

//

Now, w.r.t. the original question of when we should use const vs.
immutable:

- For local variables, there's no practical difference between const and
  immutable, because by definition the current function holds the only
  reference to it, so there can't be any mutable reference to it. I
  would just use immutable in this case -- the compiler may be able to
  optimize the code better knowing that there can't be any mutable
  reference anywhere else (though in theory the compiler should have
  already figured this out, since it's a local variable).

- For function parameters, I would always use const over immutable,
  unless there was a reason I want to guarantee that nobody else holds a
  mutable reference to that argument (e.g., I'm storing the reference in
  a data structure that requires the data not to be mutated afterwards).
  Using const makes the function usable with both mutable and immutable
  arguments, which is more flexible when you don't need to guarantee
  that the data will never be changed by anybody.

  Some people may prefer `in` instead of const for function parameters:
  it's more self-documenting, and if you use -preview=in, it means
  `const scope`, which adds an additional check that you don't
  accidentally leak reference to parameters past the scope of the
  function.


T

-- 
Windows 95 was a joke, and Windows 98 was the punchline.


Re: DIP 1038--"@mustUse" (formerly "@noDiscard")--Accepted

2022-02-09 Thread forkit via Digitalmars-d-announce

On Wednesday, 9 February 2022 at 17:40:31 UTC, jmh530 wrote:
On Wednesday, 9 February 2022 at 16:21:24 UTC, Paul Backus 
wrote:

[snip]

In D, there is no existing word for this, so from that 
perspective both "mustuse" and "nodiscard" are equally valid.


In other languages, there are multiple existing words:

- C++17: [[nodiscard]]
- C (gcc/clang): __attribute__((warn_unused_result))
- Rust: #[must_use]

If you are used to C++, then you will find "nodiscard" 
natural, and "mustuse" will require you to learn a new word. 
If you are used to Rust, then you will find "mustuse" natural, 
and "nodiscard" would have required you to learn a new word.




But what color should the bike shed be? ;)


Color is a perceptual experience, and its impact on psychological 
functioning has been well researched.


Re: DIP 1038--"@mustUse" (formerly "@noDiscard")--Accepted

2022-02-09 Thread Ola Fosheim Grøstad via Digitalmars-d-announce
On Wednesday, 9 February 2022 at 17:48:29 UTC, Guillaume Piolat 
wrote:

There is also the Nim "discard" statement.


Just change the default to not allowing return values to be 
discarded. When you really want to, do:


```
cast(void) function_with_return_value(…)
```

Or something like that.



Re: DIP 1038--"@mustUse" (formerly "@noDiscard")--Accepted

2022-02-09 Thread forkit via Digitalmars-d-announce
On Wednesday, 9 February 2022 at 17:54:17 UTC, rikki cattermole 
wrote:


On 10/02/2022 5:21 AM, Paul Backus wrote:

- C (gcc/clang): __attribute__((warn_unused_result))


C23 will also have [[nodiscard]]

Not only will it have that on functions, but also support a 
string too.


Unfortunately its looking like we have chosen to diverge from 
C, and therefore won't be completely C compatible soon.


Will be exciting as to what kind of bugs crop up because of 
this!


Exactly. So now C++ and C will have nodiscard, and when those 
developers come over to D (the developers most targetted by D 
btw), someone will have to explain why D decided on a different 
color for the bikeshed.




Re: Added copy constructors to "Programming in D"

2022-02-09 Thread Anonymouse via Digitalmars-d-announce

On Saturday, 8 January 2022 at 02:07:10 UTC, Ali Çehreli wrote:
2) The other noteworthy change in the book is my now-different 
stance on variables: Now I recommend 'const' over 'immutable' 
for variables.


I'm curious, could you elaborate a bit on this? I skimmed through 
the page on Immutability but I didn't find anything explaining it.


Re: DIP 1038--"@mustUse" (formerly "@noDiscard")--Accepted

2022-02-09 Thread Ola Fosheim Grøstad via Digitalmars-d-announce

On Wednesday, 9 February 2022 at 10:59:03 UTC, Dukc wrote:
You're implying that your opinion is rational and apolitical, 
disagreeing with it is irrational politics.


I am implying that there are many symptoms of people not being 
willing to champion the best possible design and instead have 
started to look for what they think is easy to get through. I see 
that in this DIP, in other DIPs and in comments about DIPs people 
are contemplating. The accumulated outcome of such political 
design processes are usually not great.


I will later try to create a separate thread for this, as Paul 
does not want this topic in this thread.




Re: Added copy constructors to "Programming in D"

2022-02-09 Thread Meta via Digitalmars-d-announce

Why do we even bother with `in` when we can do:

alias In(T) = const scope T;

void test(In!int n) {
pragma(msg, typeof(n));
}

?

onlineapp.d(3): Deprecation: storage class `scope` has no effect 
in type aliases

const(int)

...oh


Re: Added copy constructors to "Programming in D"

2022-02-09 Thread Ali Çehreli via Digitalmars-d-announce

On 2/9/22 18:11, Meta wrote:
> Why do we even bother with `in` when we can do:
>
> alias In(T) = const scope T;
>
> void test(In!int n) {
>  pragma(msg, typeof(n));
> }
>
> ?
>
> onlineapp.d(3): Deprecation: storage class `scope` has no effect in type
> aliases
> const(int)
>
> ...oh

I didn't know that but 'in' is underrated. There is heavy mental load on 
deciding parameter types:


// Silly const:
void foo(const(int));

// Too much information to the user (why
// do they need to know that I will mutate the parameter):
void foo(int);

// When I know that copying is expensive
// (which excludes rvalues; oops):
void foo(ref const(ExpensiveToCopy));

// When I know that the type is non-copyable,
// I have to use 'ref':
void foo(ref const(NonCopyable));

What if foo is a template? ref or const or by-value? Or inout? Always or 
sometimes?


Enough already! :)

All I want to say is "I want to use this parameter as input." I don't 
care if its rvalue or expensive to copy or impossible to copy. I will 
define it as 'ref' if that's what I want but I shouldn't be thinking 
about any of the above for function inputs.


I am happy to raise awareness of the new 'in':

  https://dlang.org/spec/function.html#in-params

'in' allows passing rvalues by ref! 'in' eliminates unwanted 
side-effects just because a function wants to use an object. 'in' passes 
non-copyable types by reference. Wow! That's engineering to my ears. :)


Having said that, there is one thing that bothers me with 'in' or 
'const'. Let's assume I want to mutate a copy of the parameter:


void foo(in int i) {
  ++i;// ERROR
}

So I must make a copy:

  auto j = i;
  ++j;// ERROR

Because 'auto' is too safe and takes 'const'. One more try:

  int j = i;
  ++j;

Or perhaps in some generic code:

  import std.traits : Unqual;
  Unqual!(typeof(i)) j = i;
  ++j;

Ok, fine.

One more thing remains: Although 'i' may be the most logical name for 
the parameter, I cannot name 'j' as 'i' so I can mangle the parameter 
name just to prevent using 'i' in the function by accident:


void foo(in int i_);

That's not good because it changes what my callers see of my function.

I can use 'i_' in the body (instead of 'j') but then I am open to the 
same mistake of using 'i' instead of 'i_' in the body. (Obviously not 
when mutating but when actually using.)


Yeah, that issue bugs me a little.

Ali