Re: const in functions

2023-03-18 Thread Salih Dincer via Digitalmars-d-learn

On Friday, 17 March 2023 at 22:41:18 UTC, Ali Çehreli wrote:

My comment was purely technical. What I meant is, if the code 
is an island where there is no single 'const' in sight, then a 
D programmer can live by ignoring 'const'. At a technical 
level...


This is different from C++ where you have to use references to 
const in order to take rvalue references as parameters. Since D 
does not allow binding rvalues even to references to const, 
this is a moot point. (-preview=in does bind rvalues to 
references as an optimization but that fact is hidden from the 
programmer.)


Let's increase the level one bit...

Again we will remain within the boundaries of `-preview=in`, but 
we will learn other hidden information. Because you get 
interesting results when you raise the issue to function 
overloading. Here's what happens when you compile the following 
example:


https://wandbox.org/permlink/XvInUjEtMKOS0CVD

1. I guess none of objects are created copy.  Because Apple has 
already `ref` and Pineapple didn't execute ctor because of `in` 
keyword.  Isn't Quince also a `const` but it was created when it 
is not a copyible object:



ref: Apple
in: Pinapple
const: Quince
0 copies... [Apple: paid, pinapple, quince]


2. If there is no function that takes `ref`, Apple prefers 
`const`. Please just hide the function under the version block. 
In this case, ctor will run once:



const: Apple
in: Pinapple
const: Quince
1 copies... [qpple, pinapple, quince]


3. If you replace `in` with `scope` (function 3) then pineapple 
and quince will also select different functions:



const: Apple
const: Pinapple
in: Quince
2 copies... [qpple, qinapple, puince]


With this example, it is possible to obtain dozens of results 
like these. I love D, D is a very powerful language.


SDB@79


Re: const in functions

2023-03-17 Thread Ali Çehreli via Digitalmars-d-learn

On 3/12/23 16:14, FozzieBear wrote:
> On Sunday, 12 March 2023 at 15:09:45 UTC, Salih Dincer wrote:
>>
>> ...
>
> So I don't agree with part of this comment (made elsewhere in this 
thread):

>
> "You can live without 'const' until your code interacts with other
> people's code."

My comment was purely technical. What I meant is, if the code is an 
island where there is no single 'const' in sight, then a D programmer 
can live by ignoring 'const'. At a technical level...


This is different from C++ where you have to use references to const in 
order to take rvalue references as parameters. Since D does not allow 
binding rvalues even to references to const, this is a moot point. 
(-preview=in does bind rvalues to references as an optimization but that 
fact is hidden from the programmer.)


So, my comment is correct at a technical level.

> Code interacts with other code. Code should always be clear as to its
> intent.

Absolutely. That's why I always start with 'const' (what should have 
been the default but is not for historical reasons):


  const foo = bar();

I change that 'const' to e.g. 'auto' as needed.

> Who wrote that code, or other code that interacts with that
> code, is irrelvant.

However, there is always the danger of going too far though. To keep the 
fun in the game, a programmer should be free to do whatever they want in 
their own code e.g. in their throw-away script programs.


Here is one line I never include in production code but I very 
frequently use in short programs:


import std;

Removes mental load, frees the mind, and enables flow of programming.

Some code is written for myself, not for people who are not watching 
over my shoulder. There is pride in caring for every character of the 
source code but sometimes freedom from all concerns is good too. 
Luckily, D makes it easy to refactor as requirements change.


Ali



Re: const in functions

2023-03-13 Thread Basile B. via Digitalmars-d-learn

On Sunday, 12 March 2023 at 15:09:45 UTC, Salih Dincer wrote:

Hi,
[...]
// A, we can get its to guarantee us that parameters
// won't change:

auto inConst(T)(T a, const T b) // const
{ // it's not needed --^ but ^-- why can't this be used



Well you got the great answers to your questions already but I 
like to add a comment that is that


**`const` parameters without `ref` are really moot.**

I whish at least that they could give the guarantee to be rvalues 
(i.e have no address) but this is actually not the case. All the 
D compilers will actually copy `const` parameters to locals, 
making them lvalues, unless optimizations are requested(1).


See codegen : https://godbolt.org/z/vev1PGWh3.

This brings the idea that maybe a `rvalue` storage class could be 
added to the language.


(1): Actually DMD does not drop the copy **at all**, even with -O.



Re: const in functions

2023-03-13 Thread Ali Çehreli via Digitalmars-d-learn

On 3/13/23 08:17, Salih Dincer wrote:

> In this case, using `ref` will increase performance while reducing the
> number of copies.

I am not sure about that. Unless there is an expensive copy 
construction, most objects are simple data copies.


To use 'ref' or not should be guided through semantics. Luckily, we have 
the -preview=in command line switch that removes the cost of copying 
from the equation:


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

Just marking the input parameters 'in' should be sufficient in most cases.

Ali



Re: const in functions

2023-03-13 Thread Salih Dincer via Digitalmars-d-learn

On Sunday, 12 March 2023 at 19:09:13 UTC, Ali Çehreli wrote:

---


In this case, using `ref` will increase performance while 
reducing the number of copies.  Would it be wise to use `const 
ref` to protect the routine from ourselves or someone else? For 
example:


```d
auto inConst(
  //const
  ref Int a, const ref Int b)
{
  a.x += 1;
  return Int(a.x + b.x);
}

struct Foo(T) {
  T x;
  alias x this;
  this(T n) { x = n; }
}
alias Int = Foo!int;
```

SDB@79


Re: const in functions

2023-03-12 Thread FozzieBear via Digitalmars-d-learn

On Sunday, 12 March 2023 at 15:09:45 UTC, Salih Dincer wrote:


...


So I don't agree with part of this comment (made elsewhere in 
this thread):


"You can live without 'const' until your code interacts with 
other people's code."


Code interacts with other code. Code should always be clear as to 
its intent. Who wrote that code, or other code that interacts 
with that code, is irrelvant.


As for the issue of 'const' itelf, I refer you to a thoughtful 
article on this matter:


(I'm not saying I agree with this article, or that I don't agree, 
I'm just referring it to you to make your own judgements.


http://www.jmdavisprog.com/articles/why-const-sucks.html



Re: const in functions

2023-03-12 Thread Ali Çehreli via Digitalmars-d-learn

On 3/12/23 08:09, Salih Dincer wrote:

> As someone who has used const very little in my life

You can live without 'const' until your code interacts with other 
people's code. For example, the following program works just fine:


struct S {
int * p;

void foo() {}
}

void bar(S s) {}

void main() {
auto s = S();
s.foo();
bar(s);
}

Now you replace (or a user of your code replaces) 'auto' with 'const' 
and you will get 2 compilation errors:


const s = S();
s.foo();// ERROR 1
bar(s); // ERROR 2

So, if your code will ever interact with other people's code it must be 
const-correct. If foo() is not mutating the object (including through 
the p member), it better be defined as 'const':


void foo() const {}

And if bar() is not mutating the parameter, it better take as const:

void bar(const(S) s) {}

Now the code compiles.

You can (and should) use 'const' everywhere that you can because it 
increases the usability of code: Mutable, 'const', and 'immutable' 
variables can be used with code that takes by 'const'.


This is not the same with code taking by 'immutable'. It can only be 
used with 'immutable' variables.


Ali



Re: const in functions

2023-03-12 Thread Hipreme via Digitalmars-d-learn

On Sunday, 12 March 2023 at 15:09:45 UTC, Salih Dincer wrote:

Hi,

As someone who has used const very little in my life, I want to 
learn and ask: What are consts used in function parameters for; 
isn't there a copy already?





Const is used for you not be able to change your values inside 
references. This is why we have const methods for example:


```d

class Test
{
private int a;
int getA() const {return a;}
}
```

By having this property in your method, it says you're 
guaranteeing that Test won't be changed when this method is 
called, then, it'll be less time trying to find what mutated the 
object, so, use it as much as you can, but never overuse it since 
it is a pain to deal with.


Const for value types is also used for not mutating them inside 
the function also leading to less debugging.


Another use case for them is for compiler being able to infer 
some optimizations. If your variable is `immutable`, it becomes 
implicitly `__gshared`, which does not uses Thread Local Storage, 
another good thing for optimization in both memory and access.


const in functions

2023-03-12 Thread Salih Dincer via Digitalmars-d-learn

Hi,

As someone who has used const very little in my life, I want to 
learn and ask: What are consts used in function parameters for; 
isn't there a copy already?


```d
/*
 * Here's we have a class (Foo is partially simple):
 */
class Foo(T) {
  T x; // <--- Because gonna just an int field!

  this(T n) { x = n; }

  override
  string toString() {
import std.conv : text;
return x.text;
  }
}
alias Int = Foo!int; // more simple...

import std.stdio : writeln;
import std.traits: isMutable;

/*
 * Let's simply use and test it!
 */
void main()
{
  auto n = new Int(41);
  auto r = (new Int(1)).inConst(n);/*
  auto r = (new Int(1)).outConst(n);
  assert( r.x == 42 &&
!isMutable!( typeof(r) )
  );//*/

  n.writeln; // "41": It still has a value of 41.
  r.writeln; // "43": Added an extra 1 as expected!
}


// A, we can get its to guarantee us that parameters
// won't change:

auto inConst(T)(T a, const T b) // const
{ // it's not needed --^ but ^-- why can't this be used

  a.x += 1; /* suppose it happened accidentally!
  ^-- it's already a new copy, right?//*/

  return new T(a.x + b.x); // Foo!int(43)
}


// B is used to guarantee that the returned result
// doesn't change:

const(T) outConst(T)(T a, T b)
{
  return new T(a.x + b.x);
}
```

In summary, we can use it in several places (in/out data, body, 
etc.) in a function. Is const needed if the compiler is copying? 
So why can't at the beginning of the body also be used and we get 
this error:


source_file.d(38): Error: function 
`source.inConst!(Foo!int).inConst` without `this` cannot be 
`const`
source_file.d(26): Error: template instance 
`source.inConst!(Foo!int)` error instantiating


I appreciate the answers given because they hold a very important 
place in my life, thank you.


SDB@79


Re: Why is it possible to call non-const member functions of rvalues but a compile error to modify members or rvalues directly?

2020-06-14 Thread Johannes Loher via Digitalmars-d-learn

On Saturday, 13 June 2020 at 12:47:31 UTC, Stanislav Blinov wrote:

[...]
The temporary exists until the end of full expression, or until 
the end of enclosing statement. It is simply not an lvalue for 
the caller, but it certainly exists, and so its interface must 
function.


So public data members are not part of the interface? I 
understand that it probably doesn't make much sense to mutate 
data members of an rvalue but this just looks very inconsistent 
to me, in particular if you consider the fact that you can also 
call member functions with the = syntax:

```
struct A
{

auto a(int _a)
{
return this._a = _a;
}

int _a = 0;
}

void main
{
static assert(__traits(compiles, { A().a = 2; })); // this is 
ok but looks like it shouldn’t be

}
```


Re: Why is it possible to call non-const member functions of rvalues but a compile error to modify members or rvalues directly?

2020-06-13 Thread Stanislav Blinov via Digitalmars-d-learn

On Saturday, 13 June 2020 at 11:26:58 UTC, Johannes Loher wrote:

Why is it a compile error to set `_a` directly but calling `a` 
just works fine?


If we prevent modifying members of rvalues directly, I would 
also expect calling non-const member functions of rvalues to be 
prevented.


1) Constructors and destructors are also member functions. Surely 
you won't suggest making all constructors `const`, and not being 
able to destruct a temporary? :)
2) The member functions may have useful side effects even on the 
state of temporary.

3) The member functions may serve as factories.

The temporary exists until the end of full expression, or until 
the end of enclosing statement. It is simply not an lvalue for 
the caller, but it certainly exists, and so its interface must 
function. Consider (this code will fail on older compilers, up to 
2.067.0, due to a bug):


void main()
{
import std.stdio : File;
import std.range : iota;
with (File("test.txt", "w"))
{
foreach (n; iota(1, 100, 5))
writeln(n);
}
}

This will open the file, write numbers [1, 96] on their own lines 
in that file, and close it. Both the File and the Iota range are 
temporaries. File can't be `const` as it's a wrapper over FILE*. 
The range can't be const since the foreach mutates it, and it is 
effectively a factory of numbers.




Why is it possible to call non-const member functions of rvalues but a compile error to modify members or rvalues directly?

2020-06-13 Thread Johannes Loher via Digitalmars-d-learn
Consider the following example:

```
struct A
{

auto a(int _a)
{
return this._a = _a;
}

int _a = 0;
}

void main()
{
static assert(!__traits(compiles, { A()._a = 2; }));
static assert(__traits(compiles, { A().a(2); }));
}
```
(https://run.dlang.io/is/GkmpA8)

Why is it a compile error to set `_a` directly but calling `a` just
works fine?

If we prevent modifying members of rvalues directly, I would also expect
calling non-const member functions of rvalues to be prevented.