Re: Mixin/static if issue

2021-08-25 Thread DLearner via Digitalmars-d-learn

On Wednesday, 25 August 2021 at 22:57:23 UTC, jfondren wrote:

Contrast:


[...]


```d
void main() {
   import std.stdio;

   uint TestVar = 5;

   string mxnWrite_Size_t(string VarName)() {

  static if (typeof(mixin(VarName)).stringof == "uint") {

 return `write("` ~ VarName ~ `");`;
  } else {

 return `writeln("Apparently TestVar not a uint");`;  
  }
   }

   mixin(mxnWrite_Size_t!"TestVar");
}
```

Output: TestVar


Confirm works for me.
Thanks!


Re: Mixin/static if issue

2021-08-25 Thread jfondren via Digitalmars-d-learn

On Wednesday, 25 August 2021 at 22:52:23 UTC, DLearner wrote:

On Wednesday, 25 August 2021 at 22:33:00 UTC, H. S. Teoh wrote:
[...}


I think what you meant to write is:

   static if (typeof(mixin(VarName)).stringof == "uint") {

You want the type of the variable named by VarName, not the 
type of VarName.



T


I understand your reasoning, but:

```
void main() {
   import std.stdio;

   uint TestVar = 5;

   string mxnWrite_Size_t(string VarName) {

  static if (typeof(mixin(VarName)).stringof == "uint") {

 return `write("` ~ VarName ~ `");`;
  } else {

 return `writeln("Apparently TestVar not a uint");`;  
  }
   }

   mixin(mxnWrite_Size_t("TestVar"));
}
```
produced Error: variable `VarName` cannot be read at compile 
time


Contrast:

```d
void main() {
   import std.stdio;

   uint TestVar = 5;

   string mxnWrite_Size_t(string VarName)() {

  static if (typeof(mixin(VarName)).stringof == "uint") {

 return `write("` ~ VarName ~ `");`;
  } else {

 return `writeln("Apparently TestVar not a uint");`;  
  }
   }

   mixin(mxnWrite_Size_t!"TestVar");
}
```

Output: TestVar


Re: Mixin/static if issue

2021-08-25 Thread DLearner via Digitalmars-d-learn

On Wednesday, 25 August 2021 at 22:33:00 UTC, H. S. Teoh wrote:
[...}


I think what you meant to write is:

   static if (typeof(mixin(VarName)).stringof == "uint") {

You want the type of the variable named by VarName, not the 
type of VarName.



T


I understand your reasoning, but:

```
void main() {
   import std.stdio;

   uint TestVar = 5;

   string mxnWrite_Size_t(string VarName) {

  static if (typeof(mixin(VarName)).stringof == "uint") {

 return `write("` ~ VarName ~ `");`;
  } else {

 return `writeln("Apparently TestVar not a uint");`;  
  }
   }

   mixin(mxnWrite_Size_t("TestVar"));
}
```
produced Error: variable `VarName` cannot be read at compile time




Re: Mixin/static if issue

2021-08-25 Thread H. S. Teoh via Digitalmars-d-learn
On Wed, Aug 25, 2021 at 10:16:39PM +, DLearner via Digitalmars-d-learn 
wrote:
> Please see below:
> ```
> void main() {
>import std.stdio;
> 
>uint TestVar = 5;
> 
>string mxnWrite_Size_t(string VarName) {
^^
Obviously, VarName is a string. Why would you expect anything else?


>   static if (typeof(VarName).stringof == "uint") {
[[...]

I think what you meant to write is:

   static if (typeof(mixin(VarName)).stringof == "uint") {

You want the type of the variable named by VarName, not the type of
VarName.


T

-- 
Many open minds should be closed for repairs. -- K5 user


Mixin/static if issue

2021-08-25 Thread DLearner via Digitalmars-d-learn

Please see below:
```
void main() {
   import std.stdio;

   uint TestVar = 5;

   string mxnWrite_Size_t(string VarName) {

  static if (typeof(VarName).stringof == "uint") {

 return `write("` ~ VarName ~ `");`;
  } else {

 return `writeln("Apparently TestVar not a uint");`;  
  }
   }

   mixin(mxnWrite_Size_t("TestVar"));
}
```
What I expected was the string "TestVar".
What I got was the "Apparently..." error message.
Please, why is this?



Re: foreach() behavior on ranges

2021-08-25 Thread H. S. Teoh via Digitalmars-d-learn
On Wed, Aug 25, 2021 at 04:46:54PM +, Joseph Rushton Wakeling via 
Digitalmars-d-learn wrote:
> On Wednesday, 25 August 2021 at 10:59:44 UTC, Steven Schveighoffer wrote:
> > structs still provide a mechanism (postblit/copy ctor) to properly
> > save a forward range when copying, even if the guts need copying
> > (unlike classes). In general, I think it was a mistake to use
> > `.save` as the mechanism, as generally `.save` is equivalent to
> > copying, so nobody does it, and code works fine for most ranges.
> 
> Consider a struct whose internal fields are just a pointer to its
> "true" internal state.  Does one have any right to assume that the
> postblit/copy ctor would necessarily deep-copy that?
[...]
> If that struct implements a forward range, though, and that pointed-to
> state is mutated by iteration of the range, then it would be
> reasonable to assume that the `save` method MUST deep-copy it, because
> otherwise the forward-range property would not be respected.
[...]

What I understand from what Andrei has said in the past, is that a range
is merely a "view" into some underlying storage; it is not responsible
for the contents of that storage.  My interpretation of this is that
.save will only save the *position* of the range, but it will not save
the contents it points to, so it will not (should not) deep-copy.

However, if the range is implemented by a struct that contains a
reference to its iteration state, then yes, to satisfy the definition of
.save it should deep-copy this state.


> With that in mind, I am not sure it's reasonable to assume that just
> because a struct implements a forward-range API, that copying the
> struct instance is necessarily the same as saving the range.
[...]

Andrei has mentioned before that in retrospect, .save was a design
mistake.  The difference between an input range and a forward range
should have been keyed on whether the range type has reference semantics
(input range) or by-value semantics (forward range).  But for various
reasons, including the state of the language at the time the range API
was designed, the .save route was chosen, and we're stuck with it unless
Phobos 2.0 comes into existence.

Either way, though, the semantics of a forward range pretty much
dictates that whatever type a range has, if it claims to be a forward
range then .save must preserve whatever iteration state it has at that
point in time. If this requires deep-copying some state referenced from
a struct, then that's what it takes to satisfy the API.  This may take
the form of a .save method that copies state, or a copy ctor that does
the same, or simply storing iteration state as PODs in the range struct
so that copying the struct equates to preserving the iteration state.


T

-- 
Why waste time reinventing the wheel, when you could be reinventing the engine? 
-- Damian Conway


Re: foreach() behavior on ranges

2021-08-25 Thread Joseph Rushton Wakeling via Digitalmars-d-learn
On Wednesday, 25 August 2021 at 17:01:54 UTC, Steven 
Schveighoffer wrote:
In a world where copyability means it's a forward range? Yes. 
We aren't in that world, it's a hypothetical "if we could go 
back and redesign".


OK, that makes sense.

Technically this is true. In practice, it rarely happens. The 
flaw of `save` isn't that it's an unsound API, the flaw is that 
people get away with just copying, and it works 99.9% of the 
time. So code is simply untested with ranges where `save` is 
important.


This is very true, and makes it quite reasonable to try to pursue 
"the obvious/lazy thing == the thing you're supposed to do" 
w.r.t. how ranges are defined.


I'd be willing to bet $10 there is a function in phobos right 
now, that takes forward ranges, and forgets to call `save` when 
iterating with foreach. It's just so easy to do, and works with 
most ranges in existence.


I'm sure you'd win that bet!


The idea is to make the meaning of a range copy not ambiguous.


Yes, this feels reasonable.  And then one can reserve the idea of 
a magic deep-copy method for special cases like pseudo-RNGs where 
one wants them to be copyable on user request, but without code 
assuming it can copy them.


Re: foreach() behavior on ranges

2021-08-25 Thread Steven Schveighoffer via Digitalmars-d-learn

On 8/25/21 12:46 PM, Joseph Rushton Wakeling wrote:

On Wednesday, 25 August 2021 at 10:59:44 UTC, Steven Schveighoffer wrote:
structs still provide a mechanism (postblit/copy ctor) to properly 
save a forward range when copying, even if the guts need copying 
(unlike classes). In general, I think it was a mistake to use `.save` 
as the mechanism, as generally `.save` is equivalent to copying, so 
nobody does it, and code works fine for most ranges.


Consider a struct whose internal fields are just a pointer to its "true" 
internal state.  Does one have any right to assume that the 
postblit/copy ctor would necessarily deep-copy that?


In a world where copyability means it's a forward range? Yes. We aren't 
in that world, it's a hypothetical "if we could go back and redesign".


If that struct implements a forward range, though, and that pointed-to 
state is mutated by iteration of the range, then it would be reasonable 
to assume that the `save` method MUST deep-copy it, because otherwise 
the forward-range property would not be respected.


With that in mind, I am not sure it's reasonable to assume that just 
because a struct implements a forward-range API, that copying the struct 
instance is necessarily the same as saving the range.


Technically this is true. In practice, it rarely happens. The flaw of 
`save` isn't that it's an unsound API, the flaw is that people get away 
with just copying, and it works 99.9% of the time. So code is simply 
untested with ranges where `save` is important.


Indeed, IIRC quite a few Phobos library functions program defensively 
against that difference by taking a `.save` copy of their input before 
iterating over it.


I'd be willing to bet $10 there is a function in phobos right now, that 
takes forward ranges, and forgets to call `save` when iterating with 
foreach. It's just so easy to do, and works with most ranges in existence.




What should have happened is that input-only ranges should not have 
been copyable, and copying should have been the save mechanism. Then 
it becomes way way more obvious what is happening. Yes, this means 
forgoing classes as ranges.


I think there's a benefit of a method whose definition is explicitly "If 
you call this, you will get a copy of the range which will replay 
exactly the same results when iterating over it".  Just because the 
meaning of "copy" can be ambiguous, whereas a promise about how 
iteration can be used is not.


The idea is to make the meaning of a range copy not ambiguous.

-Steve


Re: foreach() behavior on ranges

2021-08-25 Thread Joseph Rushton Wakeling via Digitalmars-d-learn
On Wednesday, 25 August 2021 at 10:59:44 UTC, Steven 
Schveighoffer wrote:
structs still provide a mechanism (postblit/copy ctor) to 
properly save a forward range when copying, even if the guts 
need copying (unlike classes). In general, I think it was a 
mistake to use `.save` as the mechanism, as generally `.save` 
is equivalent to copying, so nobody does it, and code works 
fine for most ranges.


Consider a struct whose internal fields are just a pointer to its 
"true" internal state.  Does one have any right to assume that 
the postblit/copy ctor would necessarily deep-copy that?


If that struct implements a forward range, though, and that 
pointed-to state is mutated by iteration of the range, then it 
would be reasonable to assume that the `save` method MUST 
deep-copy it, because otherwise the forward-range property would 
not be respected.


With that in mind, I am not sure it's reasonable to assume that 
just because a struct implements a forward-range API, that 
copying the struct instance is necessarily the same as saving the 
range.


Indeed, IIRC quite a few Phobos library functions program 
defensively against that difference by taking a `.save` copy of 
their input before iterating over it.


What should have happened is that input-only ranges should not 
have been copyable, and copying should have been the save 
mechanism. Then it becomes way way more obvious what is 
happening. Yes, this means forgoing classes as ranges.


I think there's a benefit of a method whose definition is 
explicitly "If you call this, you will get a copy of the range 
which will replay exactly the same results when iterating over 
it".  Just because the meaning of "copy" can be ambiguous, 
whereas a promise about how iteration can be used is not.


Re: scope(exit) with expected library

2021-08-25 Thread WebFreak001 via Digitalmars-d-learn
On Wednesday, 25 August 2021 at 15:30:57 UTC, Steven 
Schveighoffer wrote:

[...]

Another approach is to let the compiler deal with the error 
handling and not muddy your return type. Swift does something 
similar, where it rewrites the throw/catch into a standard 
return and doesn't do actual thrown exceptions. There are some 
caveats, but if we could fit this kind of error handling into 
mostly-similar syntax (i.e. the same ease of exceptions without 
the actual problems that exceptions and stack unwinding bring), 
it might make things much easier to transition.


-Steve


I like the Swift error handling, so I think this would be a great 
idea for nothrow code with error handling too.


Re: scope(exit) with expected library

2021-08-25 Thread Steven Schveighoffer via Digitalmars-d-learn

On 8/25/21 10:58 AM, WebFreak001 wrote:



Hm I'm not quite seeing how the error handler is related to an "Expected 
type interface" that the compiler could expect.


This would be without compiler changes.

Currently with exceptions the scope things are implemented using 
try-catch-finally, this would be even simpler:


```d
scope(exit) exit();
scope(success) success();
scope(failure) failure();

return something();
```

lowers to

```d
auto ret = something();
if (ret.isError) failure();
if (!ret.isError) success();
exit();
return ret;
```

for all return statements.

I might be missing some obvious drawbacks here but I think this sounds 
reasonable and comparable with the try-catch-finally lowering.


It does sound pretty reasonable. But overloading these existing features 
might make things confusing.




As Paul Backus suggested the compiler could check if the return type has 
for example `is(typeof(return.isError) : bool)` and maybe also if the 
function is `nothrow`.


Another approach is to let the compiler deal with the error handling and 
not muddy your return type. Swift does something similar, where it 
rewrites the throw/catch into a standard return and doesn't do actual 
thrown exceptions. There are some caveats, but if we could fit this kind 
of error handling into mostly-similar syntax (i.e. the same ease of 
exceptions without the actual problems that exceptions and stack 
unwinding bring), it might make things much easier to transition.


-Steve


Re: scope(exit) with expected library

2021-08-25 Thread Paul Backus via Digitalmars-d-learn
On Wednesday, 25 August 2021 at 14:42:07 UTC, Steven 
Schveighoffer wrote:


I think it's possible to work with some mechanics that aren't 
necessarily desirable. Something like:


```d
ErrorHandler error = registerErrorHandler;
error.onFailure({writeln("division failed");});
error.onSuccess({writeln("division succeeded");});

...
```


This is kind of like what Common Lisp has with its condition 
system. One downside of this approach in D is that it would not 
work well with static analysis features like `@safe`, `nothrow`, 
etc., since the handlers are not known until runtime. But it does 
offer a lot more flexibility than traditional exceptions.





Re: scope(exit) with expected library

2021-08-25 Thread WebFreak001 via Digitalmars-d-learn
On Wednesday, 25 August 2021 at 14:52:34 UTC, Steven 
Schveighoffer wrote:

On 8/25/21 10:42 AM, Steven Schveighoffer wrote:



I think it's possible to work with some mechanics that aren't 
necessarily desirable. Something like:




One has to weigh how much this is preferred to actual exception 
handling...


If something like DIP1008 could become usable, it might 
alleviate even the need for such things.


-Steve


DIP1008 is a nice step forward, but I think sometimes explicit 
error handling is nicer, and especially with C interop and 
concurrency (like vibe.d tasks) `nothrow` is pretty good to have.


Re: scope(exit) with expected library

2021-08-25 Thread WebFreak001 via Digitalmars-d-learn
On Wednesday, 25 August 2021 at 14:42:07 UTC, Steven 
Schveighoffer wrote:

On 8/25/21 10:22 AM, Paul Backus wrote:
On Wednesday, 25 August 2021 at 14:04:54 UTC, WebFreak001 
wrote:

[...]


Probably the only principled way to make this work would be to 
define some kind of "concept"/structural interface that's 
recognized by the compiler to mean "this is an error-handling 
type", in the same way that the compiler recognizes 
`empty`/`front`/`popFront` to mean "this is an iterable type".


Even then, it would require some pretty invasive language 
changes (and some pretty gnarly code in the compiler), but 
it's at least *theoretically* possible.


I think it's possible to work with some mechanics that aren't 
necessarily desirable. Something like:


```d
ErrorHandler error = registerErrorHandler;
error.onFailure({writeln("division failed");});
error.onSuccess({writeln("division succeeded");});

...
```

On returning `err`, the registration would trigger a flag 
saying an error is occurring, and call the right callback when 
`ErrorHandler` is destructing. The cleanup of the return value 
would clean up the error condition. It would be messy and 
likely brittle.


Hm I'm not quite seeing how the error handler is related to an 
"Expected type interface" that the compiler could expect.


Currently with exceptions the scope things are implemented using 
try-catch-finally, this would be even simpler:


```d
scope(exit) exit();
scope(success) success();
scope(failure) failure();

return something();
```

lowers to

```d
auto ret = something();
if (ret.isError) failure();
if (!ret.isError) success();
exit();
return ret;
```

for all return statements.

I might be missing some obvious drawbacks here but I think this 
sounds reasonable and comparable with the try-catch-finally 
lowering.


As Paul Backus suggested the compiler could check if the return 
type has for example `is(typeof(return.isError) : bool)` and 
maybe also if the function is `nothrow`.


Re: scope(exit) with expected library

2021-08-25 Thread Steven Schveighoffer via Digitalmars-d-learn

On 8/25/21 10:42 AM, Steven Schveighoffer wrote:



I think it's possible to work with some mechanics that aren't 
necessarily desirable. Something like:




One has to weigh how much this is preferred to actual exception handling...

If something like DIP1008 could become usable, it might alleviate even 
the need for such things.


-Steve


Re: scope(exit) with expected library

2021-08-25 Thread Steven Schveighoffer via Digitalmars-d-learn

On 8/25/21 10:22 AM, Paul Backus wrote:

On Wednesday, 25 August 2021 at 14:04:54 UTC, WebFreak001 wrote:
Would it be possible to extend `scope(exit)` and `scope(success)` to 
trigger properly for functions returning `Expected!T` as defined in 
the [expectations](https://code.dlang.org/packages/expectations) and 
[expected](https://code.dlang.org/packages/expected) DUB libraries?


For example is it possible to make this work as expected:
```d
Expected!int divide(int a, int b) nothrow
{
    scope (failure) writeln("division failed");
    scope (success) writeln("division succeeded");

    if (b == 0) return err!int("division by zero");
    return ok(a / b);
}
```


Probably the only principled way to make this work would be to define 
some kind of "concept"/structural interface that's recognized by the 
compiler to mean "this is an error-handling type", in the same way that 
the compiler recognizes `empty`/`front`/`popFront` to mean "this is an 
iterable type".


Even then, it would require some pretty invasive language changes (and 
some pretty gnarly code in the compiler), but it's at least 
*theoretically* possible.


I think it's possible to work with some mechanics that aren't 
necessarily desirable. Something like:


```d
ErrorHandler error = registerErrorHandler;
error.onFailure({writeln("division failed");});
error.onSuccess({writeln("division succeeded");});

...
```

On returning `err`, the registration would trigger a flag saying an 
error is occurring, and call the right callback when `ErrorHandler` is 
destructing. The cleanup of the return value would clean up the error 
condition. It would be messy and likely brittle.


I've also advocated in the past that it would be nice to have access to 
the things that are causing the success, failure, etc.


Like `scope(failure, exception) writeln("Exception being thrown is ", 
exception)`


Could be extended to:

```d
scope(success, r) if(r.isError) writeln("division failed");
  else  writeln("division succeeded");
```

That `scope(success)` kinda sucks though...

-Steve


Re: Emacs AutoComplete Tutorial Video for D Language

2021-08-25 Thread WebFreak001 via Digitalmars-d-learn

On Monday, 23 August 2021 at 17:59:44 UTC, Mahdi wrote:
I made this video for people asking how to configure Dlang in 
Emacs environment:) :


https://peertube.linuxrocks.online/w/62pWpmw2r4Se1XvmYiWm75


cool, I think you might wanna post this in General or Announce 
instead so more people see it!


Though I think it would be useful having this as text form as 
well, which is probably a bit better suited for a setup like 
this. A text tutorial accompanied with the video may also allow 
you to cut out big text sections from the video.


Personally I think it would be best if there was speech in your 
video as well. I saw you are non-English, you could actually use 
this as an advantage. There are much less D resources in 
non-English languages, making a tutorial in your own native 
language could allow more people to learn and discover D.


Re: scope(exit) with expected library

2021-08-25 Thread WebFreak001 via Digitalmars-d-learn

On Wednesday, 25 August 2021 at 14:22:26 UTC, Paul Backus wrote:

On Wednesday, 25 August 2021 at 14:04:54 UTC, WebFreak001 wrote:

[...]


Probably the only principled way to make this work would be to 
define some kind of "concept"/structural interface that's 
recognized by the compiler to mean "this is an error-handling 
type", in the same way that the compiler recognizes 
`empty`/`front`/`popFront` to mean "this is an iterable type".


Even then, it would require some pretty invasive language 
changes (and some pretty gnarly code in the compiler), but it's 
at least *theoretically* possible.


do you think this would be worth a DIP that could get in? Or 
should usage in these packages grow first?


Re: scope(exit) with expected library

2021-08-25 Thread Paul Backus via Digitalmars-d-learn

On Wednesday, 25 August 2021 at 14:04:54 UTC, WebFreak001 wrote:
Would it be possible to extend `scope(exit)` and 
`scope(success)` to trigger properly for functions returning 
`Expected!T` as defined in the 
[expectations](https://code.dlang.org/packages/expectations) 
and [expected](https://code.dlang.org/packages/expected) DUB 
libraries?


For example is it possible to make this work as expected:
```d
Expected!int divide(int a, int b) nothrow
{
scope (failure) writeln("division failed");
scope (success) writeln("division succeeded");

if (b == 0) return err!int("division by zero");
return ok(a / b);
}
```


Probably the only principled way to make this work would be to 
define some kind of "concept"/structural interface that's 
recognized by the compiler to mean "this is an error-handling 
type", in the same way that the compiler recognizes 
`empty`/`front`/`popFront` to mean "this is an iterable type".


Even then, it would require some pretty invasive language changes 
(and some pretty gnarly code in the compiler), but it's at least 
*theoretically* possible.


scope(exit) with expected library

2021-08-25 Thread WebFreak001 via Digitalmars-d-learn
Would it be possible to extend `scope(exit)` and `scope(success)` 
to trigger properly for functions returning `Expected!T` as 
defined in the 
[expectations](https://code.dlang.org/packages/expectations) and 
[expected](https://code.dlang.org/packages/expected) DUB 
libraries?


For example is it possible to make this work as expected:
```d
Expected!int divide(int a, int b) nothrow
{
scope (failure) writeln("division failed");
scope (success) writeln("division succeeded");

if (b == 0) return err!int("division by zero");
return ok(a / b);
}
```


Re: Profiling

2021-08-25 Thread René Zwanenburg via Digitalmars-d-learn

On Tuesday, 24 August 2021 at 10:33:07 UTC, JG wrote:

The reason for the crash boils down to the fact that this fails:

foreach(k; sort!"a > b"(funcs.keys)) assert(k in funcs);

funcs is of type ubyte[4][float]

Is this a compiler bug?


That assert will fail if there are NaN keys in the AA. This for 
example will print null:


```d
bool[float] aa;
aa[float.nan] = true;
writeln(float.nan in aa);
```

Sort may also act funny when NaNs are involved, not sure about 
that.


Re: alias this - am I using it wrong?

2021-08-25 Thread Johann Lermer via Digitalmars-d-learn

On Wednesday, 25 August 2021 at 12:23:06 UTC, Adam D Ruppe wrote:
...

Thanks - that explains in all.

On Wednesday, 25 August 2021 at 12:23:32 UTC, FeepingCreature 
wrote:



class Alias_Class
{
Test_Struct ts;
Test_Struct getter() { return ts; }
alias getter this;
}


Good idea, that should solve my current problem. The reason for 
having an alias this was that I had a C data type 
(cairo_surface_t) that I transferred into a class and I'm using 
the alias so that I don't need to rewrite the whole application 
at once. Unfortunately I overlooked some code that resulted in a 
seg fault - and I was lost at understanding why.


Re: alias this - am I using it wrong?

2021-08-25 Thread jmh530 via Digitalmars-d-learn

On Wednesday, 25 August 2021 at 12:23:06 UTC, Adam D Ruppe wrote:

[snip]


That's a lot about alias this that I didn't know. Thanks.


Re: alias this - am I using it wrong?

2021-08-25 Thread FeepingCreature via Digitalmars-d-learn

On Wednesday, 25 August 2021 at 12:11:01 UTC, Johann Lermer wrote:

Hi all,

I have a little problem understanding alias this. I always 
thought, that alias this only makes implicit conversions from 
the aliased object to this. Then, why do lines 18 and 22 
compile in the code below? And, btw, line 22 crashes with a 
segmentation fault.


```d
01 struct Test_Struct {long t;}
02
03 class Alias_Class
04 {
05 Test_Struct ts;
06 alias ts this;
07 }
08
09 class Test_Class
10 {
11 Alias_Class ac;
12 }
13
14 void main ()
15 {
16 auto ac = new Alias_Class;
17 Test_Struct ts = ac;  // compiles
18 ac = ts;  // compiles as well - why?
19
20 auto tc = new Test_Class;
21 ts = tc.ac;   // compiles
22 tc.ac = ts;   // again this compiles, but seg 
faults

23 }
```

Johann


ts is a field. You can assign to a field. So when the field is 
aliased to this, you can assign to the field through a class 
reference.


You can disable this behavior by creating a getter in 
Alias_Class, then aliasing it to this:


```
class Alias_Class
{
Test_Struct ts;
Test_Struct getter() { return ts; }
alias getter this;
}
```



Re: alias this - am I using it wrong?

2021-08-25 Thread Adam D Ruppe via Digitalmars-d-learn

On Wednesday, 25 August 2021 at 12:11:01 UTC, Johann Lermer wrote:
I have a little problem understanding alias this. I always 
thought, that alias this only makes implicit conversions from 
the aliased object to this.


What it does is if "a SOMETHING b" doesn't compile, it instead 
tries "a.alias_this_member SOMETHING b" instead, or "a SOMETHING 
b.alias_this_member" instead if that's on the other side. The 
object with alias this must already exist though, so constructors 
are an exception (though another object's constructor can trigger 
some existing object's alias this when used as a param to that).


The "SOMETHING" there can be operators like + or = or a .member.

Only if both fail to compile do you actually get an error.


17 Test_Struct ts = ac;  // compiles


So what really happens here is the compiler sees ts = ac; fails 
to compile, so it is rewritten into "ts = ac.ts;"



18 ac = ts;  // compiles as well - why?


So ac = ts fails, meaning it rewrites into `ac.ts = ts;`


20 auto tc = new Test_Class;
21 ts = tc.ac;   // compiles


So here it is rewritten into `ts = tc.ac.ts`.

22 tc.ac = ts;   // again this compiles, but seg 
faults


And now

tc.ac.ts = ts;

is the rewrite since the plain one didn't compile, thus accessing 
the null member.




Note too that alias this can be to a function, in which case the 
rewrite will call the function.


Implicit conversion isn't really what alias this is about. It 
kinda works (though note with a alias this struct it can be 
passed by value and thus copy, again the compiler just does the 
rewrite). It is just giving transparent access to a member.


Re: alias this - am I using it wrong?

2021-08-25 Thread jfondren via Digitalmars-d-learn

On Wednesday, 25 August 2021 at 12:11:01 UTC, Johann Lermer wrote:

```d
14 void main ()
15 {
16 auto ac = new Alias_Class;
17 Test_Struct ts = ac;  // compiles
18 ac = ts;  // compiles as well - why?
19
20 auto tc = new Test_Class;
21 ts = tc.ac;   // compiles
22 tc.ac = ts;   // again this compiles, but seg 
faults

23 }
```


line 17: ac.ts is copied into main's ts
line 18: main's ts is copied back into ac.ts

You can confirm this by changing t, doing the copy, and then 
checking t.


line 21: segfaults because tc.ac is null, and you're trying to 
copy tc.ac.ts into main's ts


alias this - am I using it wrong?

2021-08-25 Thread Johann Lermer via Digitalmars-d-learn

Hi all,

I have a little problem understanding alias this. I always 
thought, that alias this only makes implicit conversions from the 
aliased object to this. Then, why do lines 18 and 22 compile in 
the code below? And, btw, line 22 crashes with a segmentation 
fault.


```d
01 struct Test_Struct {long t;}
02
03 class Alias_Class
04 {
05 Test_Struct ts;
06 alias ts this;
07 }
08
09 class Test_Class
10 {
11 Alias_Class ac;
12 }
13
14 void main ()
15 {
16 auto ac = new Alias_Class;
17 Test_Struct ts = ac;  // compiles
18 ac = ts;  // compiles as well - why?
19
20 auto tc = new Test_Class;
21 ts = tc.ac;   // compiles
22 tc.ac = ts;   // again this compiles, but seg 
faults

23 }
```

Johann



Re: foreach() behavior on ranges

2021-08-25 Thread Steven Schveighoffer via Digitalmars-d-learn

On 8/25/21 7:26 AM, Alexandru Ermicioi wrote:

On Wednesday, 25 August 2021 at 11:04:35 UTC, Steven Schveighoffer wrote:
It never has called `save`. It makes a copy, which is almost always 
the equivalent `save` implementation.




Really?

Then what is the use for .save method then?
The only reason I can find is that you can't declare constructors in 
interfaces hence the use of the .save method instead of copy constructor 
for defining forward ranges.


The `save` function was used to provide a way for code like 
`isForwardRange` to have a definitive symbol to search for. It's also 
opt-in, whereas if we used copying, it would be opt-out.


Why a function, and not just some enum? Because it should be something 
that has to be used, not just a "documenting" attribute if I recall 
correctly.


Keep in mind, UDAs were not a thing yet, and compile-time introspection 
was not as robust as it is now. I'm not even sure you could disable copying.




We have now two ways of doing the same thing, which can cause confusion. 
Best would be then for ranges to hide copy constructor under private 
modifier (or disable altoghether), and force other range wrappers call 
.save always, including foreach since by not doing so we introduce 
difference in behavior between ref and value forward ranges (for foreach 
use).


There would be a huge hole in this plan -- arrays. Arrays are the most 
common range anywhere, and if a forward range must not be copyable any 
way but using `save`, it would mean arrays are not forward ranges.


Not to mention that foreach on an array is a language construct, and 
does not involve the range interface.


-Steve


Re: foreach() behavior on ranges

2021-08-25 Thread Alexandru Ermicioi via Digitalmars-d-learn
On Wednesday, 25 August 2021 at 11:04:35 UTC, Steven 
Schveighoffer wrote:
It never has called `save`. It makes a copy, which is almost 
always the equivalent `save` implementation.


-Steve


Really?

Then what is the use for .save method then?
The only reason I can find is that you can't declare constructors 
in interfaces hence the use of the .save method instead of copy 
constructor for defining forward ranges.


We have now two ways of doing the same thing, which can cause 
confusion. Best would be then for ranges to hide copy constructor 
under private modifier (or disable altoghether), and force other 
range wrappers call .save always, including foreach since by not 
doing so we introduce difference in behavior between ref and 
value forward ranges (for foreach use).





Re: foreach() behavior on ranges

2021-08-25 Thread Steven Schveighoffer via Digitalmars-d-learn

On 8/25/21 6:06 AM, Alexandru Ermicioi wrote:

On Wednesday, 25 August 2021 at 08:15:18 UTC, frame wrote:

I know, but foreach() doesn't call save().


Hmm, this is a regression probably, or I missed the time frame when 
foreach moved to use of copy constructor for forward ranges.


Do we have a well defined description of what input, forward and any 
other well known range is, and how it does interact with language features?


For some reason I didn't manage to find anything on dlang.org.


It never has called `save`. It makes a copy, which is almost always the 
equivalent `save` implementation.


-Steve


Re: foreach() behavior on ranges

2021-08-25 Thread Steven Schveighoffer via Digitalmars-d-learn

On 8/25/21 4:31 AM, frame wrote:

On Tuesday, 24 August 2021 at 21:15:02 UTC, Steven Schveighoffer wrote:
I'm surprised you bring PHP as an example, as it appears their foreach 
interface works EXACTLY as D does:


Yeah, but the point is, there is a rewind() method. That is called every 
time on foreach().


It seems what you are after is forward ranges. Those are able to 
"rewind" when you are done with them. It's just not done through a 
rewind method, but via saving the range before iteration:


```d
foreach(val; forwardRange.save)
{
   ...
   break;
}

// forwardRange hasn't been iterated here
```

-Steve


Re: foreach() behavior on ranges

2021-08-25 Thread Steven Schveighoffer via Digitalmars-d-learn

On 8/25/21 6:06 AM, Joseph Rushton Wakeling wrote:

On Tuesday, 24 August 2021 at 09:15:23 UTC, bauss wrote:
A range should be a struct always and thus its state is copied when 
the foreach loop is created.


That's quite a strong assumption, because its state might be a reference 
type, or it might not _have_ state in a meaningful sense -- consider an 
input range that wraps reading from a socket, or that just reads from 
`/dev/urandom`, for two examples.


Deterministic copying per foreach loop is only guaranteed for forward 
ranges.


structs still provide a mechanism (postblit/copy ctor) to properly save 
a forward range when copying, even if the guts need copying (unlike 
classes). In general, I think it was a mistake to use `.save` as the 
mechanism, as generally `.save` is equivalent to copying, so nobody does 
it, and code works fine for most ranges.


What should have happened is that input-only ranges should not have been 
copyable, and copying should have been the save mechanism. Then it 
becomes way way more obvious what is happening. Yes, this means forgoing 
classes as ranges.


-Steve


Re: foreach() behavior on ranges

2021-08-25 Thread Joseph Rushton Wakeling via Digitalmars-d-learn

On Tuesday, 24 August 2021 at 09:15:23 UTC, bauss wrote:
A range should be a struct always and thus its state is copied 
when the foreach loop is created.


That's quite a strong assumption, because its state might be a 
reference type, or it might not _have_ state in a meaningful 
sense -- consider an input range that wraps reading from a 
socket, or that just reads from `/dev/urandom`, for two examples.


Deterministic copying per foreach loop is only guaranteed for 
forward ranges.


Re: foreach() behavior on ranges

2021-08-25 Thread Alexandru Ermicioi via Digitalmars-d-learn

On Wednesday, 25 August 2021 at 08:15:18 UTC, frame wrote:

I know, but foreach() doesn't call save().


Hmm, this is a regression probably, or I missed the time frame 
when foreach moved to use of copy constructor for forward ranges.


Do we have a well defined description of what input, forward and 
any other well known range is, and how it does interact with 
language features?


For some reason I didn't manage to find anything on dlang.org.


Re: foreach() behavior on ranges

2021-08-25 Thread Alexandru Ermicioi via Digitalmars-d-learn

On Wednesday, 25 August 2021 at 06:51:36 UTC, bauss wrote:
Of course it doesn't disallow classes but it's generally 
advised that you use structs and that's what you want in 99% of 
the cases. It's usually a red flag when a range starts being a 
reference type.


Well, sometimes you can't avoid ref types. For example when you 
need to mask the implementation of the range, but yes, in most of 
the cases best is to use simpler methods to represent ranges.


Re: foreach() behavior on ranges

2021-08-25 Thread frame via Digitalmars-d-learn
On Tuesday, 24 August 2021 at 21:15:02 UTC, Steven Schveighoffer 
wrote:



If you have a for loop:

```d
int i;
for(i = 0; i < someArr.length; ++i)
{
   if(someArr[i] == desiredValue) break;
}
```

You are saying, "compiler, please execute the `++i` when I 
break from the loop because I already processed that one". How 
can that be expected? I would *never* expect that. When I 
break, it means "stop the loop, I'm done", and then I use `i` 
which is where I expected it to be.


I get your point, you see foreach() as raw translate to the 
for-loop and I'm fine with that. To automatically popFront() on 
break also is only a suggestion if there is no other mechanism to 
the tell the range we have cancelled it.




It becomes useless for foreach() because you can't rely on 
them if other code breaks the loop and you need to use that 
range, like in my case. But also for ranges - there is no need 
for a popFront() if it is not called in a logic way. Then even 
empty() could fetch next data if needed. It only makes sense 
if language system code uses it in a strictly order and 
ensures that this order is always assured.


There is no problem with the ordering. What seems to be the 
issue is that you aren't used to the way ranges work.


Ehm, no...
-> empty()
-> front()
-> popFront()
-> empty()
-> front()
break;

-> empty();
-> front();

clearly violates the order for me.
Well, nobody said that we must move on the range - but come on...


What's great about D is that there is a solution for you:

```d
struct EagerPopfrontRange(R)
{
   R source;
   ElementType!R front;
   bool empty;
   void popFront() {
 if(source.empty) empty = true;
 else {
front = source.front;
source.popFront;
 }
   }
}

auto epf(R)(R inputRange) {
   auto result = EagerPopfrontRange!R(inputRange);
   result.popFront; // eager!
   return result;
}

// usage
foreach(v; someRange.epf) { ... }
```

Now if you break from the loop, the original range is pointing 
at the element *after* the one you last were processing.


This is nice. But foreach() should do it automatically - avoiding 
this.
foreach() should be seen as a special construct that does that, 
not just a dumb alias for the for-loop. Why? Because it is a 
convenient language construct and usage should be easy. Again, 
there should be no additional popFront() just because I break the 
loop.



I'm surprised you bring PHP as an example, as it appears their 
foreach interface works EXACTLY as D does:


Yeah, but the point is, there is a rewind() method. That is 
called every time on foreach().





Re: foreach() behavior on ranges

2021-08-25 Thread frame via Digitalmars-d-learn
On Tuesday, 24 August 2021 at 18:52:19 UTC, Alexandru Ermicioi 
wrote:


Forward range exposes also capability to create save points, 
which is actually used by foreach to do, what it is done in 
java by iterable interface for example.


I know, but foreach() doesn't call save().




Re: foreach() behavior on ranges

2021-08-25 Thread bauss via Digitalmars-d-learn
On Tuesday, 24 August 2021 at 19:06:44 UTC, Alexandru Ermicioi 
wrote:

On Tuesday, 24 August 2021 at 09:15:23 UTC, bauss wrote:


A range should be a struct always and thus its state is copied 
when the foreach loop is created.


Actually the range contracts don't mention that it needs to be 
a by value type. It can also be a reference type, i.e. a class.




Of course it doesn't disallow classes but it's generally advised 
that you use structs and that's what you want in 99% of the 
cases. It's usually a red flag when a range starts being a 
reference type.