Re: Why do immutable variables need reference counting?

2022-04-11 Thread Ali Çehreli via Digitalmars-d-learn

On 4/11/22 05:57, wjoe wrote:

> To my understanding immutable data should reside in a separate data
> segment which itself could reside in ROM.

We are getting into implementation details which a programming language 
acts as not to care (but has to do especially when it's a system 
programming language like D. :) ).


> So when the variable, or 'pointer' to the data, goes out of scope just
> the 'pointer' is gone, the actual data unreachable, but still there.

I think it translates to the destructor never being executed. Otherwise, 
nobody would even know whether the memory location is reused for other 
pursposes later on.


> Due to its immutable nature immutable data can't be changed and this, to
> my understanding, includes deallocation.

D one language where object lifetime is deliberately separate from 
memory allocation.


> And because the data could be
> in ROM any modification is an error.

Fully agreed. However, how could I initialize such an object then? (You 
may have meant a read-only memory page instead of ROM.)


> immutable data on the fly doesn't make sense to me - that should be
> const's domain.

Even 'const' cause confusions because it's used in at least two 
different ways (even e.g. in C++):


1) I will not mutate data through this reference. For example, a 
parameter that is pointer to const achieves that:


  void foo (const(int)[] arr);

2) This variable is const:

  const i = 42;

Well, there is the confusion: There is no "reference" in the second case 
at all!


I don't agree with you when you say immutability should be const's 
domain because const covers item 1 above as well, where there is no 
immutability of data whatsoever. The data may be perfectly mutable or 
immutable, where my access will be readonly.


Perhaps you are saying the same thing but enters D's immutable: The data 
is immutable.


immutable data on the fly can be very useful because e.g. it makes 
multithreaded programming trivial in some cases by removing the need for 
locking.


> Strings, I know. But the way things are, I hardly see a
> difference between immutable and const.

Imagine a File struct that holds on to a file name. In C++, we would 
have to make a copy of the constructor argument for two reasons:


1) Lifetime of the object might be short. This is not a problem in D 
because of the GC.


2) The data might change after I start holding on to it through a 
reference. This is not a problem *only if* data were immutable because 
my const parameter cannot preclude the producer from mutating it 
further. Example:


import std.stdio;
import std.format;

struct S {
  const(char)[] fileName;

  this(const(char)[] fileName) {
this.fileName = fileName;
report();
  }

  ~this() {
report();
  }

  void report(string func = __FUNCTION__) {
writefln!"%s working with %s."(func, fileName);
  }
}

void main() {
  char[] fileName = "foo.txt".dup;
  auto s = S(fileName);
  fileName[0..3] = "bar";
}

The output shows that the file name changed between construction and 
destruction:


deneme.S.this working with foo.txt.
deneme.S.~this working with bar.txt.

If fileName were immutable, then the owner would not be able to mutate 
anyway, so the struct could get away without copying the file name.


Ali



Re: Why do immutable variables need reference counting?

2022-04-11 Thread Ali Çehreli via Digitalmars-d-learn

On 4/11/22 08:02, Paul Backus wrote:

> any pointers or references

To add, Salih and I were in an earlier discussion where that concept 
appeared as "indirections."


Ali



Re: Why do immutable variables need reference counting?

2022-04-11 Thread Paul Backus via Digitalmars-d-learn

On Monday, 11 April 2022 at 12:12:39 UTC, Salih Dincer wrote:

It worked for me in a different way.


1 is (about to be) alive!

2 is (already) dead.
2 is (already) dead.
2 is (already) dead.


2 is (already) dead.

2 is (already) dead.
Hello D!
1 is (already) dead.

Because I changed the code like this.

```d

struct S
{
  . . .

  string toString() { return ""; }
}

//S test(inout S s)/*
S test(S s)//*/
{
  s.i = 2;
  return s;
}

void main()
{
  immutable s = S(1);
  test(s).writeln;
  "Hello".writefln!"%s D!";
}
```

If the inout is set, it does not allow compilation.


Because `S` does not contain any pointers or references, you are 
allowed to create a mutable *copy* of an `S` from an `immutable` 
source. That's what happens when you pass it to `test`.


The extra destructor calls come from the copies made by `test` 
and `writeln`. If you add a copy constructor, you can see this 
happening in the output:


```d
struct S {

/* ... */

this(ref inout typeof(this) other) inout {
this.i = other.i;
writeln(i, " was copied.");
}
}
```

```
1 is (about to be) alive!
1 was copied.
2 was copied.
2 is (already) dead.
2 was copied.
2 was copied.
2 was copied.
2 is (already) dead.
2 is (already) dead.

2 is (already) dead.
2 is (already) dead.
Hello D!
1 is (already) dead.
```

1 constructor call + 5 copies = 6 destructor calls.


Re: arsd-minigui - couple of questions

2022-04-11 Thread sai via Digitalmars-d-learn

On Monday, 11 April 2022 at 13:14:16 UTC, Adam D Ruppe wrote:

On Monday, 11 April 2022 at 12:40:29 UTC, sai wrote:
One more request, is it possible for you to do to ImageBox 
what you did to Button to show the transparent images (png)? 
Because Imagebox is showing black color for transparent pixels.


oh yeah this one is different because the imagebox custom draws 
it, so it is really as simple as passing `true` to the opacity 
there too when it converts.


Try this diff:

https://github.com/adamdruppe/arsd/commit/912047ccdda7e7775f64431a631519e6024d2494

i think it fixes it, let me know.


Done, it works. Awesome thanks.



Re: arsd-minigui - couple of questions

2022-04-11 Thread Adam D Ruppe via Digitalmars-d-learn

On Monday, 11 April 2022 at 12:40:29 UTC, sai wrote:
One more request, is it possible for you to do to ImageBox what 
you did to Button to show the transparent images (png)? Because 
Imagebox is showing black color for transparent pixels.


oh yeah this one is different because the imagebox custom draws 
it, so it is really as simple as passing `true` to the opacity 
there too when it converts.


Try this diff:

https://github.com/adamdruppe/arsd/commit/912047ccdda7e7775f64431a631519e6024d2494

i think it fixes it, let me know.


Re: Why do immutable variables need reference counting?

2022-04-11 Thread wjoe via Digitalmars-d-learn

On Monday, 11 April 2022 at 03:24:11 UTC, Ali Çehreli wrote:

On 4/10/22 20:05, norm wrote:
> On Sunday, 10 April 2022 at 23:19:47 UTC, rikki cattermole
wrote:

> In my mind immutable data
> means the data will not change and neither will the result of
reading
> that data, ever.

Yes.

> I don't get how you can have thread safety guarantees based
on immutable
> if reading that data in a thread suddenly becomes undefined
behaviour
> and could return anything.

Yes, it would be a bug to attempt to read data that is not live 
anymore.


> That isn't immutable then.

The lifetime of immutable data can start and end.

import std.stdio;

struct S {
  int i;

  this(int i) {
this.i = i;
writeln(i, " is (about to be) alive!");
  }

  ~this() {
writeln(i, " is (already) dead.");
  }
}

void main() {
  foreach (i; 0 .. 3) {
immutable s = S(i);
  }
}

The output:

0 is (about to be) alive!
0 is (already) dead.
1 is (about to be) alive!
1 is (already) dead.
2 is (about to be) alive!
2 is (already) dead.

Module-level immutable and 'static const' would live much 
longer but they have a lifetime as well. However, today, the 
destructor cannot be executed on an immutable object, so I 
remove the qualifiers with cast(), which sohuld be undefined 
behavior (today?).


immutable(S) moduleS;

shared static this() {
  moduleS = S(42);
}

shared static ~this() {
  destroy(cast()moduleS);
}

void main() {
}

> Once instantiated
> immutable data persists for the remainder of the program.

That seems to be the misunderstanding. Again, I think 
module-level 'immutable' and 'static const' data fits that 
description.


> You may not
> have access if the variable goes out of scope, but if you do
it will
> always be there and always return the same value when you
read from memory.

That description fits D's GC-owned data (including immutables). 
The lifetime ends when there is no reference to it.


Another example is immutable messages passed between threads 
with std.concurrency: That kind of data clearly originates at 
run time and the receiving end keeps the data alive as long as 
it needs.


Ali


To my understanding immutable data should reside in a separate 
data segment which itself could reside in ROM.
So when the variable, or 'pointer' to the data, goes out of scope 
just the 'pointer' is gone, the actual data unreachable, but 
still there.
Due to its immutable nature immutable data can't be changed and 
this, to my understanding, includes deallocation. And because the 
data could be in ROM any modification is an error. How would you 
deallocate ROM anyways?
Your foreach could be unrolled at compile time, however it could 
easily be changed to a runtime only loop but this entire concept 
of creating immutable data on the fly doesn't make sense to me - 
that should be const's domain. Strings, I know. But the way 
things are, I hardly see a difference between immutable and const.


Re: arsd-minigui - couple of questions

2022-04-11 Thread sai via Digitalmars-d-learn
One more request, is it possible for you to do to ImageBox what 
you did to Button to show the transparent images (png)? Because 
Imagebox is showing black color for transparent pixels.


I tried to see the git history to see if I can make that change 
to Imagebox and submit a pull request, but I am lost and don't 
think I understand the code well enough.


Re: Importing version identifiers from another file?

2022-04-11 Thread wjoe via Digitalmars-d-learn

On Monday, 11 April 2022 at 08:57:12 UTC, KytoDragon wrote:

[...]
Sadly this results in an identifier conflict, as the version 
set in config.d does not seem to affect library.d. Is there any 
way to import version specifiers from a separate file? I don't 
want to pollute the users build files (dub.json etc.) with 
dozens of versions they need to pass to the compiler.


No, version identifiers don't escape module scope.
See 24.1.4 https://dlang.org/spec/version.html for reference.


Re: Why do immutable variables need reference counting?

2022-04-11 Thread Salih Dincer via Digitalmars-d-learn

On Monday, 11 April 2022 at 03:24:11 UTC, Ali Çehreli wrote:


The output:

0 is (about to be) alive!
0 is (already) dead.
1 is (about to be) alive!
1 is (already) dead.
2 is (about to be) alive!
2 is (already) dead.


It worked for me in a different way.


1 is (about to be) alive!

2 is (already) dead.
2 is (already) dead.
2 is (already) dead.


2 is (already) dead.

2 is (already) dead.
Hello D!
1 is (already) dead.

Because I changed the code like this.

```d

struct S
{
  . . .

  string toString() { return ""; }
}

//S test(inout S s)/*
S test(S s)//*/
{
  s.i = 2;
  return s;
}

void main()
{
  immutable s = S(1);
  test(s).writeln;
  "Hello".writefln!"%s D!";
}
```

If the inout is set, it does not allow compilation.

Thanks, SDB79


Re: Lambdas Scope

2022-04-11 Thread Timon Gehr via Digitalmars-d-learn

On 11.04.22 11:11, Salih Dincer wrote:
How is this possible? Why is it compiled? Don't the same names in the 
same scope conflict?


```d
int function(int) square;
void main()
{
   square = (int a) => a * a;
   int square = 5.square;
   assert(square == 25);
}
```

Thanks, SDB@79


- Local variables in a function can hide variables in less nested 
scopes. (Such hiding is only an error for nested block scopes within the 
same function.)


- UFCS always looks up names in module scope, it does not even check locals.


Re: Lambdas Scope

2022-04-11 Thread user1234 via Digitalmars-d-learn

On Monday, 11 April 2022 at 09:11:06 UTC, Salih Dincer wrote:
How is this possible? Why is it compiled? Don't the same names 
in the same scope conflict?


```d
int function(int) square;
void main()
{
  square = (int a) => a * a;
  int square = 5.square;
  assert(square == 25);
}
```

Thanks, SDB@79


you can use explicit call parenthesis to make the difference 
between the local var and the global func. Also you have the 
module access operator and the fully qualified name as 
alternatives to select the one you wish to.





Lambdas Scope

2022-04-11 Thread Salih Dincer via Digitalmars-d-learn
How is this possible? Why is it compiled? Don't the same names in 
the same scope conflict?


```d
int function(int) square;
void main()
{
  square = (int a) => a * a;
  int square = 5.square;
  assert(square == 25);
}
```

Thanks, SDB@79


Re: Why do immutable variables need reference counting?

2022-04-11 Thread user1234 via Digitalmars-d-learn

On Sunday, 10 April 2022 at 23:05:24 UTC, norm wrote:

Hi All,

I am clearly misunderstanding something fundamental, and 
probably obvious :D


Reading some of the discussions on __metadata I was wondering 
if someone could explain why a immutable reference counting 
type is needed. By definition a reference counter cannot be 
immutable, so what would be the use case that requires it? It 
cannot really be pure nor safe either because the ref goes out 
of scope and the allocation is freed. How is this immutable?



Thanks,
Norm


refcounting would require a concept of "tail const" / "tail 
immutable" so that transitivity of the qualifier does not affect 
the data used to refcount (basically the field that hold the 
count) but only the data that **are** refcounted.


Importing version identifiers from another file?

2022-04-11 Thread KytoDragon via Digitalmars-d-learn
I am currently maintaining a port of a c++ library that uses 
conditional compilation to integrate into the users program. e.g.:


config.h (edited by the user of the library)
```
#define USE_MY_ASSERT
void MY_ASSERT(bool expr) {...}
```

library.c
```
include "config.h"
#ifndef USE_MY_ASSERT
void MY_ASSERT(bool expr) {...} // default implementation
#end
```

Given that static if at top-level has been broken for some time 
(https://issues.dlang.org/show_bug.cgi?id=17883, 
https://issues.dlang.org/show_bug.cgi?id=20905, 
https://issues.dlang.org/show_bug.cgi?id=21171), I tried to use 
version identifiers for this in D:


config.d
```
version = USE_MY_ASSERT;
void MY_ASSERT(bool expr) {...}
```

library.d
```
import config;
version (USE_MY_ASSERT) {} else {
void MY_ASSERT(bool expr) {...}
}
```

Sadly this results in an identifier conflict, as the version set 
in config.d does not seem to affect library.d. Is there any way 
to import version specifiers from a separate file? I don't want 
to pollute the users build files (dub.json etc.) with dozens of 
versions they need to pass to the compiler.


Re: Why do immutable variables need reference counting?

2022-04-11 Thread IGotD- via Digitalmars-d-learn

On Sunday, 10 April 2022 at 23:19:47 UTC, rikki cattermole wrote:


immutable isn't tied to lifetime semantics.

It only says that this memory will never be modified by anyone 
during its lifetime.


Anyway, the real problem is with const. Both mutable and 
immutable become it automatically.


I was thinking about that, often when using const you use it when 
passing parameters to functions. This is essentially borrowing. 
The situation is similar with C++ with unique_ptr and shared_ptr. 
Often C++ interfaces use const* when using pointers and not their 
smart pointer counterparts, so essentially the ownership remains, 
while "borrowing" are using raw pointers. A C++ interface only 
accepts the smart pointers when you want to change ownership. D 
could use a similar approach, when using pointers/references you 
shouldn't alter the internal data including reference count.


What I would interested in is if D could have move by default 
depending on type. In this case the RC pointer wrapper could be 
move by default. Increasing is only done when calling "clone" 
(similar to Rust). This way RC increases are optimized naturally. 
What I don't want from Rust is the runtime aliasing check 
(RefCell) on at all times. I rather go with that the compiler 
assumes no aliasing but the programmer is responsible for this. 
You can have runtime aliasing/borrowing check in debug mode but 
in release build it can be removed. This is similar to bounds 
checking where you can choose to have it or not.