Re: Proper way to handle "alias this" deprecation for classes

2023-05-17 Thread Salih Dincer via Digitalmars-d-learn

On Wednesday, 17 May 2023 at 08:00:17 UTC, Dom DiSc wrote:

If you want auto-conversion, you should be more explicit:
```d
float opCast() { }
```
because if you return "auto" it is not the highest-prio fit and 
therefore not chosen.
If you have multiple choices, you still don't need to use 
"auto". Instead you can return T:

```d
T opCast(T)() if(isFloatingPoint!T)
{
   return cast(T)num / cast(T)den; // float, double or real
}
```
Kind of ironic, but especially "auto" does NOT fit 
automatically :-)


Sorry for not expressing myself better.  Let me try to explain 
with another example:


```d
struct RightShift
{
  int num, shr;

  T opCast(T : char)()
   => cast(T)(num >> shr);
}
import std.stdio;
void main()
{
  auto f = RightShift(128, 2);
  char chr = cast(char)f | '\1';
  assert(chr == '!');
  
  //char test = f; // Error: cannot implicitly convert expression
  //assert(test == ' '); // `f` of type `RightShift` to `char`
}
```

This snippet works fine.  But hidden the code gives an error.  
The reason is that the compiler ignores the explicitly specified 
lines without using auto.


SDB@79


Re: Proper way to handle "alias this" deprecation for classes

2023-05-17 Thread Dom DiSc via Digitalmars-d-learn

On Friday, 12 May 2023 at 15:00:48 UTC, Salih Dincer wrote:


```d
struct Fraction {
int num, den;

this(int n, int d)
{
num = n;
den = d;
}

// Cast Expression : convert float value of fraction
auto opCast(T : float)() const
{
return cast(float)(num) / cast(float)(den);
}
}
```


If you want auto-conversion, you should be more explicit:
```d
float opCast() { }
```
because if you return "auto" it is not the highest-prio fit and 
therefore not chosen.
If you have multiple choices, you still don't need to use "auto". 
Instead you can return T:

```d
T opCast(T)() if(isFloatingPoint!T)
{
   return cast(T)num / cast(T)den; // float, double or real
}
```
Kind of ironic, but especially "auto" does NOT fit automatically 
:-)


Re: Proper way to handle "alias this" deprecation for classes

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

On Sunday, 7 May 2023 at 21:04:05 UTC, Inkrementator wrote:
Open question to everybody: What you're opinion on using opCast 
for this? Since it's a type conversion, it seems fitting to me.


Can't converting without explicitly specifying in D is a big 
shortcoming in my opinion. There is such a thing as implicitly 
convertion though, but it's very confusing. I don't see that 
simplicity in C++ in the D codes!


```CPP
#include 
using namespace std;
struct Fraction {
int num, den;

Fraction(int n, int d) {
num = n;
den = d;
}

// Conversion operator: return float value of fraction
operator float() const
{
return float(num) / float(den);
}
};

int main()
{
Fraction f(2, 5);
float val = f;
cout << val << '\n'; // 0.4
return 0;
}
```

You should do the same in D like this:

```d
struct Fraction {
int num, den;

this(int n, int d)
{
num = n;
den = d;
}

// Cast Expression : convert float value of fraction
auto opCast(T : float)() const
{
return cast(float)(num) / cast(float)(den);
}
}

import std.stdio;

int main()
{
auto f = Fraction(2, 5);
float val = cast(float)f;
val.writeln; //0.4
return 0;
}
```

SDB@79



Re: Proper way to handle "alias this" deprecation for classes

2023-05-10 Thread H. S. Teoh via Digitalmars-d-learn
On Wed, May 10, 2023 at 10:57:13PM +, Chris Piker via Digitalmars-d-learn 
wrote:
> On Wednesday, 10 May 2023 at 20:25:48 UTC, H. S. Teoh wrote:
> > On Wed, May 10, 2023 at 07:56:10PM +, Chris Piker via
> > Digitalmars-d-learn wrote: [...]
> > I also suffer from left/right confusion, and always have to pause to
> > think about which is the right(!) word before uttering it.
> Oh, I though was the only one with that difficulty.  Glad to hear I'm
> not alone. :-)

:-)


> I have a tendency to think of things by their purpose when programming
> but not by their location on the line or page.  So terms such as
> "writable" versus "ephemeral" or "addressable" versus "temporary" (or
> "register"), make so much more sense to me.

Yeah TBH I was never a fan of the lvalue/rvalue terminology. In a
hypothetical language where the arguments to an assignment operator is
reversed, the terminology would become needlessly confusing. E.g., if
there was an operator `X => Y;` that means "assign the value of X to Y",
then the roles of lvalues/rvalues would be reversed.


> Back on the ref issue for a moment... I'd imagine that asking the
> compiler to delay creating a writable variable until it finds out that
> a storage location is actually needed by subsequent statements, is a
> tall order. So D chose to introduce programmers to lvalues and rvalues
> head-on, instead of creating a leaky abstraction.

It depends on how you look at it. The very concept of a variable in
memory is actually already an abstraction. Modern compilers may
enregister variables or even completely elide them. Assignments may be
reordered, and the CPU may execute things out-of-order (as long as
semantics are preserved). Intermediate values may not get stored at all,
but get folded into the larger computation and perhaps merged with some
other operation with the resulting compound operation mapped to a single
CPU instruction, etc.. So in that sense the compiler is quite capable of
figuring out what to do...

But what it can't do is read the programmer's mind to deduce the intent
of his code. Exact semantics must be somehow conveyed to the compiler,
and sad to say humans aren't very good at being exact. Often we *think*
we know exactly what the computation is, but in reality we gloss over
low-level details that will make a big difference in the outcome of the
computation in the corner cases. The whole rvalue/lvalue business is
really more a way of conveying to the compiler what exactly must happen,
rather than directly corresponding to any actual feature in the
underlying physical machine.


T

-- 
Computerese Irregular Verb Conjugation: I have preferences.  You have biases.  
He/She has prejudices. -- Gene Wirchenko


Re: Proper way to handle "alias this" deprecation for classes

2023-05-10 Thread Chris Piker via Digitalmars-d-learn

On Wednesday, 10 May 2023 at 20:25:48 UTC, H. S. Teoh wrote:
On Wed, May 10, 2023 at 07:56:10PM +, Chris Piker via 
Digitalmars-d-learn wrote: [...]
I also suffer from left/right confusion, and always have to 
pause to think about which is the right(!) word before uttering 
it.
Oh, I though was the only one with that difficulty.  Glad to hear 
I'm not alone. :-)


I have a tendency to think of things by their purpose when 
programming but not by their location on the line or page.  So 
terms such as "writable" versus "ephemeral" or "addressable" 
versus "temporary" (or "register"), make so much more sense to me.


Back on the ref issue for a moment... I'd imagine that asking the 
compiler to delay creating a writable variable until it finds out 
that a storage location is actually needed by subsequent 
statements, is a tall order. So D chose to introduce programmers 
to lvalues and rvalues head-on, instead of creating a leaky 
abstraction.


Re: Proper way to handle "alias this" deprecation for classes

2023-05-10 Thread H. S. Teoh via Digitalmars-d-learn
On Wed, May 10, 2023 at 07:56:10PM +, Chris Piker via Digitalmars-d-learn 
wrote:
[...]
> My problem with the terms lvalue and rvalue is much more basic, and is
> just a personal one that only affects probably 0.1% of people.  I just
> can't keep left vs. right straight in real life.  "Right" in my head
> always means "correct".
> 
> My daughter hates it when I'm telling her which way to turn the car
> since I've said the wrong direction so many times. :)

I also suffer from left/right confusion, and always have to pause to
think about which is the right(!) word before uttering it. :-D  Would
compass directions be more helpful? (wvalue vs. evalue) Or would it
suffer from the same problem?

(One could retroactively rationalize it as *w*ritable value vs.
*e*phemeral value. :-P)


T

-- 
By understanding a machine-oriented language, the programmer will tend to use a 
much more efficient method; it is much closer to reality. -- D. Knuth


Re: Proper way to handle "alias this" deprecation for classes

2023-05-10 Thread Chris Piker via Digitalmars-d-learn

On Wednesday, 10 May 2023 at 16:01:40 UTC, H. S. Teoh wrote:

x   =   y;
^   ^
|   |
lvalue  rvalue


...

// This is OK:
x = y + 1;

// This is not OK:
(y + 1) = x;


Thanks for the clear explanation.

My problem with the terms lvalue and rvalue is much more basic, 
and is just a personal one that only affects probably 0.1% of 
people.  I just can't keep left vs. right straight in real life.  
"Right" in my head always means "correct".


My daughter hates it when I'm telling her which way to turn the 
car since I've said the wrong direction so many times. :)





Re: Proper way to handle "alias this" deprecation for classes

2023-05-10 Thread H. S. Teoh via Digitalmars-d-learn
On Wed, May 10, 2023 at 03:24:48PM +, Chris Piker via Digitalmars-d-learn 
wrote:
[...]
> It's off topic, but I forget why managing memory for rvalues* was
> pushed onto the programmer and not handled by the compiler.  I'm sure
> there is a good reason but it does seem like a symmetry breaking
> requirement.
> 
> --
> *or was it lvalues, I can never keep the two separate.  Wish the some
> other terminology was adopted long ago, such as "named" vs.
> "ephemeral".

x   =   y;
^   ^
|   |
lvalue  rvalue

An lvalue is simply something that can appear on the *l*eft side of an
assignment statement, and an rvalue is something that appears on the
*r*ight side of an assignment statement.

It seems trivially obvious, but has far-reaching consequences. For one
thing, to be an lvalue means that you must be able to assign a value to
it. I.e., it must be a variable that exists somewhere in memory; `1 =
x;` is illegal because `1` is a literal with no memory associated with
it, so you cannot assign a new value to it.

For something to be an rvalue means that it's a value like `1` that may
not necessarily have a memory address associated with it. For example,
the value of a computation is an rvalue:

// This is OK:
x = y + 1;

// This is not OK:
(y + 1) = x;

The value of a computation cannot be assigned to, it makes no sense.
Therefore, given an rvalue, you are not guaranteed that assignment is
legal.

Note however, that given an lvalue, you can always get an rvalue out of
it. In the first example above, `y` can be an lvalue because it's a
variable with a memory location. However, it can also be used as an
rvalue.  Or, if you like, `x = y;` contains an implicit "cast" of y to
an rvalue.  But you can never turn an rvalue back into an lvalue.


T

-- 
It's bad luck to be superstitious. -- YHL


Re: Proper way to handle "alias this" deprecation for classes

2023-05-10 Thread Chris Piker via Digitalmars-d-learn

On Wednesday, 10 May 2023 at 14:42:50 UTC, Inkrementator wrote:

On Sunday, 7 May 2023 at 21:12:22 UTC, Chris Piker wrote:

https://gist.github.com/run-dlang/9b7aec72710b1108fc8277789776962a


Thanks for posting that.  Reading over the code I'm reminded that 
I never cared whether something was an rvalue or lvalue before 
writing D code.


It's off topic, but I forget why managing memory for rvalues* was 
pushed onto the programmer and not handled by the compiler.  I'm 
sure there is a good reason but it does seem like a symmetry 
breaking requirement.


--
*or was it lvalues, I can never keep the two separate.  Wish the 
some other terminology was adopted long ago, such as "named" vs. 
"ephemeral".




Re: Proper way to handle "alias this" deprecation for classes

2023-05-10 Thread Inkrementator via Digitalmars-d-learn

On Sunday, 7 May 2023 at 21:12:22 UTC, Chris Piker wrote:
On the other hand, your first suggestion of using opCast() does 
seem like a reasonable choice to me.  Can you provide a short 
code snippet using opCast to achieve the same result?


I've never used it, and particularly I know that I don't know 
whether making the the return type of opCast ref can lead to 
issues down the road and whether the template specialization is 
dangerous, as it will trigger for all types implicitly 
convertible to int* (whatever they are)


Another potential future pitfall I discovered is that code might 
break if you change your class into a struct.


Code example is in a gist since the system thinks I've added HTML 
entities to it and won't let me post it:


https://gist.github.com/run-dlang/9b7aec72710b1108fc8277789776962a


Re: Proper way to handle "alias this" deprecation for classes

2023-05-07 Thread Ali Çehreli via Digitalmars-d-learn

On 5/7/23 13:44, Chris Piker wrote:

> to fix the problem I
> just delete the alias this line from dpq2, see what unit tests and app
> code it breaks, then fix each of those.

Yes but I neglected the lvalue/rvalue issue. In some cases the code 
won't compile if the return type of the newly written explicit function 
is not 'ref'. For example, the 'ref' below is essential for the 
following use case:


class C {
int* result;

// HERE
ref asIntPtr() {
return result;
}
}

auto main() {
auto c = new C();

int i;
c.asIntPtr = &i;
assert(c.result == &i);
}

> "Programming in D" for a bright young programming
> student I know in appreciation.

Very kind of you! :)

Ali



Re: Proper way to handle "alias this" deprecation for classes

2023-05-07 Thread Chris Piker via Digitalmars-d-learn

On Sunday, 7 May 2023 at 21:04:05 UTC, Inkrementator wrote:

On Sunday, 7 May 2023 at 18:19:04 UTC, Ali Çehreli wrote:
alias this is for implicit type conversions, which can be 
achieved explicitly as well.


Open question to everybody: What you're opinion on using opCast 
for this? Since it's a type conversion, it seems fitting to me.


And another suggestion: Wrap the class in a struct that has 
visibility on the class members via the "package" access 
specifier and continue using "alias this".


Hi Inkrementator

In this case, ResponseContainer is already a wrapper structure, 
so on the surface, putting a wrapper on a wrapper feels like 
over-engineering.


On the other hand, your first suggestion of using opCast() does 
seem like a reasonable choice to me.  Can you provide a short 
code snippet using opCast to achieve the same result?







Re: Proper way to handle "alias this" deprecation for classes

2023-05-07 Thread Inkrementator via Digitalmars-d-learn

On Sunday, 7 May 2023 at 18:19:04 UTC, Ali Çehreli wrote:
alias this is for implicit type conversions, which can be 
achieved explicitly as well.


Open question to everybody: What you're opinion on using opCast 
for this? Since it's a type conversion, it seems fitting to me.


And another suggestion: Wrap the class in a struct that has 
visibility on the class members via the "package" access 
specifier and continue using "alias this".


Re: Proper way to handle "alias this" deprecation for classes

2023-05-07 Thread Chris Piker via Digitalmars-d-learn

On Sunday, 7 May 2023 at 18:19:04 UTC, Ali Çehreli wrote:

auto main() {
auto c = new C();

// The same type conversion is now explicit:
foo(c.asIntPtr);
}


Hi Ali

Ah, very clear explanation, thanks!  So basically to fix the 
problem I just delete the alias this line from dpq2, see what 
unit tests and app code it breaks, then fix each of those.  
Actually seems straightforward, for a limited code base anyway.


On a side note, with all the free help you've provided, it's 
about time I gave back.  Since I've no free time or expertise to 
offer, I picked up a hardcover copy of "Programming in D" for a 
bright young programming student I know in appreciation.


Cheers,




Re: Proper way to handle "alias this" deprecation for classes

2023-05-07 Thread Ali Çehreli via Digitalmars-d-learn

On 5/7/23 10:55, Chris Piker wrote:

> According to dmd 2.103, alias this is
> deprecated for classes, so I'd like to correct the problem.

alias this is for implicit type conversions, which can be achieved 
explicitly as well. Given the following old code:


class C {
int* result;

alias result this;
}

void foo(int*) {
}

auto main() {
auto c = new C();

// Implicit type conversion from C to int*:
foo(c);
}

One can use a member function instead:

class C {
int* result;

auto asIntPtr() {
return result;
}
}

void foo(int*) {
}

auto main() {
auto c = new C();

// The same type conversion is now explicit:
foo(c.asIntPtr);
}

Ali



Proper way to handle "alias this" deprecation for classes

2023-05-07 Thread Chris Piker via Digitalmars-d-learn

Hi D

One of the dependencies for my project has a class that makes use 
of the `alias x this` construct.  According to dmd 2.103, alias 
this is deprecated for classes, so I'd like to correct the 
problem.


Is there a specific paragraph or two that I can read to find out 
what is the appropriate replacement construct?  On a related 
note, has anyone created a code maintenance guide to help 
work-a-day programmers navigate recent changes to the D language?


For reference, here's a the code in question (from dpq2, 
result.d):

```d
package immutable final class ResultContainer
{
version(Dpq2_Dynamic)
{
import dpq2.dynloader: ReferenceCounter;

private ReferenceCounter dynLoaderRefCnt;
}

// ResultContainer allows only one copy of PGresult* due to 
avoid
// double free. For the same reason this class is declared as 
final.

private PGresult* result;
alias result this;   //< Deprecation Warning Here
package this(immutable PGresult* r)
{
assert(r);

result = r;
version(Dpq2_Dynamic) dynLoaderRefCnt = 
ReferenceCounter(true);

}

...
```

Thanks for any pointers,



Re: public vs private alias this

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

On Tuesday, 1 November 2022 at 23:01:57 UTC, Per Nordlöw wrote:

When is it preferrable to use

```d
struct S { private T t; alias t this; }
```

instead of

```d
struct S { public T t; alias t this; }
```

for any given type `T`?


If the `alias this` needs to work outside the module where `S` is 
defined, you must make the member variable `public`. So in almost 
all cases, the second form is the correct one.


public vs private alias this

2022-11-01 Thread Per Nordlöw via Digitalmars-d-learn

When is it preferrable to use

```d
struct S { private T t; alias t this; }
```

instead of

```d
struct S { public T t; alias t this; }
```

for any given type `T`?


Re: problem with alias this and Tuple

2021-10-12 Thread Mike Parker via Digitalmars-d-learn

On Tuesday, 12 October 2021 at 15:55:40 UTC, Johann Lermer wrote:
Thanks, understood. But isn't this a deficiency in the library 
that should be fixed?


The problem extends to more than just `toHash`. Take a look at 
this DConf 2019 presentation by Eduard Staniloiu on ProtoObject 
(as proposed by Andrei Alexandrescu):


https://youtu.be/EcG5mnOzZ0s

Eduard is now mentoring a Symmetry Autumn of Code participant 
(Robert Aron) whose project is implementing `ProtoObject`. You 
can get a summary of the project from Robert's first weekly 
update thread here:


https://forum.dlang.org/post/wezzcgwbnaguawzfh...@forum.dlang.org


Re: problem with alias this and Tuple

2021-10-12 Thread Paul Backus via Digitalmars-d-learn

On Tuesday, 12 October 2021 at 15:55:40 UTC, Johann Lermer wrote:
Thanks, understood. But isn't this a deficiency in the library 
that should be fixed?


You mean the part about how `Object.toHash` doesn't work with 
`const`? Yes, it is a deficiency in the library. The problem is, 
it cannot be fixed without breaking backwards compatibility.


Re: problem with alias this and Tuple

2021-10-12 Thread Johann Lermer via Digitalmars-d-learn
Thanks, understood. But isn't this a deficiency in the library 
that should be fixed?


Re: problem with alias this and Tuple

2021-10-12 Thread Paul Backus via Digitalmars-d-learn

On Tuesday, 12 October 2021 at 09:30:57 UTC, Johann Lermer wrote:

Hi all,

I have a problem with Tuples and struct templates that contain 
an alias this:

```d
import std;

struct Element(T)
{
T payload;
alias payload this;

this (T p)
{
payload = p;
}
}

class Item {}

void main ()
{
auto e = Element!Item (new Item());
auto t = tuple(e);
}
```
dmd generates a warning: **Warning: struct Element has method 
toHash, however it cannot be called with const(Element!(Item)) 
this.
Element.toHash defined here: 
/usr/local/include/d/druntime/import/object.d(83)**


The culprit seems to be the 'alias payload this'. When I remove 
that line, the code works. However, in my code, I need that 
alias. Any ideas, what's wrong or what I could do? Thanks.


All classes in D inherit from [`Object`][1], and `Object` has a 
[`toHash` method][2]. So what's happening here is (1) your `Item` 
class is inheriting `toHash` from `Object`, and (2) your 
`Element` struct is "inheriting" `toHash` from `Item` via `alias 
this`. This is why the compiler says, "struct `Element` has 
method `toHash`".


For historical reasons, `Object.toHash` is not a `const` method, 
which means it cannot be called on a `const(Object)`. So if you 
had a `const(Element!Item)` and you tried to call `.toHash` on 
it, the compiler would rewrite the call to `.payload.toHash` 
using `alias this`, and then it would fail to compile, because 
`payload` would be a `const(Item)` (a subclass of 
`const(Object)`). This is why the compiler says, "however, it 
cannot be called with `const(Element!(Item))`".


The simplest fix is to define a `toHash` method for `Element` 
using the built-in [`hashOf`][3] function:


```d
size_t toHash() const
{
return hashOf(payload);
}
```

[1]: https://druntime.dpldocs.info/object.Object.html
[2]: https://druntime.dpldocs.info/object.Object.toHash.html
[3]: https://druntime.dpldocs.info/object.hashOf.2.html


problem with alias this and Tuple

2021-10-12 Thread Johann Lermer via Digitalmars-d-learn

Hi all,

I have a problem with Tuples and struct templates that contain an 
alias this:

```d
import std;

struct Element(T)
{
T payload;
alias payload this;

this (T p)
{
payload = p;
}
}

class Item {}

void main ()
{
auto e = Element!Item (new Item());
auto t = tuple(e);
}
```
dmd generates a warning: **Warning: struct Element has method 
toHash, however it cannot be called with const(Element!(Item)) 
this.
Element.toHash defined here: 
/usr/local/include/d/druntime/import/object.d(83)**


The culprit seems to be the 'alias payload this'. When I remove 
that line, the code works. However, in my code, I need that 
alias. Any ideas, what's wrong or what I could do? Thanks.


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: seeking advice: possible new @attribute to mark class' default property to avoid alias this ?

2021-08-07 Thread someone via Digitalmars-d-learn

On Sunday, 8 August 2021 at 05:07:17 UTC, jfondren wrote:

On Sunday, 8 August 2021 at 04:51:48 UTC, someone wrote:
On Sunday, 8 August 2021 at 04:30:12 UTC, rikki cattermole 
wrote:
So a field that will automatically be resolved to as part of 
the behavior of generated toString methods.


No. A default property can be another object altogether. The 
best use case I can think of is a default collection for a 
class such as lobjComputers.computers in my example.



That really isn't what alias this is used for commonly. I.e.


I didn't know alias this even existed a month ago so I cannot 
comment for what's oftenly used; I just stated that I was 
pointed to alias this when I asked for default properties,


It might be that you were misunderstood. You're using "default 
property" as a term of art with a specific meaning, and the 
term itself looks generic enough that people can interpret it 
with their familiar meanings for 'default' and 'property'.


Probably.


This is from Visual Basic, yeah?


Actually Visual FoxPro which had a full OOP implementation, for a 
lot of reasons hated VB back then, but yes, Microsoft family of 
developer tools have them and they were practical which is not to 
say they should be good, maybe they are a terrible idea, and 
*thats* why I was asking for advice beforehand.



https://docs.microsoft.com/en-us/dotnet/visual-basic/programming-guide/language-features/procedures/how-to-declare-and-call-a-default-property

I've never run into like that before. And it doesn't seem 
well-loved in VB: "Because of these disadvantages, you should 
consider not defining default properties. For code readability, 
you should also consider always referring to all properties 
explicitly, even default properties."


This looks similar to that example:

```d
struct MsgBox {
string[] contents;
void opIndexAssign(string s, size_t i) {
if (contents.length <= i)
contents.length = i + 1;
contents[i] = s;
}
}

void main() {
import std.stdio : writeln;

MsgBox x;
x[0] = "Hello";
x[1] = " ";
x[2] = "World";
writeln(x.contents);
}
```
```


That I don't remember. But, if they were controversial back in 
the day ... I think it is all said and done ... ain't it ?





Re: seeking advice: possible new @attribute to mark class' default property to avoid alias this ?

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

On Sunday, 8 August 2021 at 04:51:48 UTC, someone wrote:
On Sunday, 8 August 2021 at 04:30:12 UTC, rikki cattermole 
wrote:
So a field that will automatically be resolved to as part of 
the behavior of generated toString methods.


No. A default property can be another object altogether. The 
best use case I can think of is a default collection for a 
class such as lobjComputers.computers in my example.



That really isn't what alias this is used for commonly. I.e.


I didn't know alias this even existed a month ago so I cannot 
comment for what's oftenly used; I just stated that I was 
pointed to alias this when I asked for default properties,


It might be that you were misunderstood. You're using "default 
property" as a term of art with a specific meaning, and the term 
itself looks generic enough that people can interpret it with 
their familiar meanings for 'default' and 'property'.


This is from Visual Basic, yeah?

https://docs.microsoft.com/en-us/dotnet/visual-basic/programming-guide/language-features/procedures/how-to-declare-and-call-a-default-property

I've never run into like that before. And it doesn't seem 
well-loved in VB: "Because of these disadvantages, you should 
consider not defining default properties. For code readability, 
you should also consider always referring to all properties 
explicitly, even default properties."


This looks similar to that example:

```d
struct MsgBox {
string[] contents;
void opIndexAssign(string s, size_t i) {
if (contents.length <= i)
contents.length = i + 1;
contents[i] = s;
}
}

void main() {
import std.stdio : writeln;

MsgBox x;
x[0] = "Hello";
x[1] = " ";
x[2] = "World";
writeln(x.contents);
}
```
```


Re: seeking advice: possible new @attribute to mark class' default property to avoid alias this ?

2021-08-07 Thread someone via Digitalmars-d-learn

On Sunday, 8 August 2021 at 04:30:12 UTC, rikki cattermole wrote:
So a field that will automatically be resolved to as part of 
the behavior of generated toString methods.


No. A default property can be another object altogether. The best 
use case I can think of is a default collection for a class such 
as lobjComputers.computers in my example.



That really isn't what alias this is used for commonly. I.e.


I didn't know alias this even existed a month ago so I cannot 
comment for what's oftenly used; I just stated that I was pointed 
to alias this when I asked for default properties, it worked, but 
later on when reading manuals/posts/etc it was obvious alias this 
was something wholly different -that's why I got rid of all alias 
this on my code, not the least when I learned of Walter's stance 
on this one.



struct ValueReference {
private {
SomethingElse* impl;
}

bool isNull() { return impl is null; }

scope ref ValueType _get() { return impl.thingy; }

alias _get this;
}

Only the problem is, this also works for classes and whole pile 
of extra cases.





Re: seeking advice: possible new @attribute to mark class' default property to avoid alias this ?

2021-08-07 Thread rikki cattermole via Digitalmars-d-learn
So a field that will automatically be resolved to as part of the 
behavior of generated toString methods.


That really isn't what alias this is used for commonly. I.e.

struct ValueReference {
private {
SomethingElse* impl;
}

bool isNull() { return impl is null; }

scope ref ValueType _get() { return impl.thingy; }

alias _get this;
}

Only the problem is, this also works for classes and whole pile of extra 
cases.


Re: seeking advice: possible new @attribute to mark class' default property to avoid alias this ?

2021-08-07 Thread someone via Digitalmars-d-learn

On Sunday, 8 August 2021 at 00:57:47 UTC, Paul Backus wrote:

On Sunday, 8 August 2021 at 00:52:43 UTC, someone wrote:

Now that I am aware of Walter's stance on alias this:

"alias this has turned out to be a mistake" @ 
https://news.ycombinator.com/item?id=28029184


... would you, I mean the community, think is it a good idea 
to file a DIP to eventually get a new attribute to 
unambiguously label a class' default property ?


Can you please explain what a "default property" is? I have 
never encountered such a thing in any other programming 
language.


```d
public class cComputer {

   private string pstrID;
   private string pstrName;

   public string ID() { return pstrID; }
   public string name() { return pstrName; }

   public void ID(const string lstrID) { pstrID = lstrID; }
   public void name(const string lstrName) { pstrName = lstrName; 
}


   this(const string lstrID, const string lstrName) {

  pstrID = lstrID;
  pstrName = lstrName;

   }

}

public class cComputers {

   private cComputer[string] pobjComputers;

   public cComputer[string] computers() { return pobjComputers; }

}

void main() {

   cComputer lobjComputer1 = new cComputer("one", "eins");
   cComputer lobjComputer2 = new cComputer("two", "zwei");
   cComputer lobjComputer3 = new cComputer("three", "drei");

   cComputers lobjComputers = new cComputers();

   lobjComputers.computers["один"] = lobjComputer1;
   lobjComputers.computers["два"] = lobjComputer2;
   lobjComputers.computers["три"] = lobjComputer3;

   assert(lobjComputers.computers["один"].ID == "one");
   foreach (cComputer lobjComputer; lobjComputers.computers) { 
writeln(lobjComputer.name); }


   /// now suppose cComputer default property is name
   /// now suppose cComputers default property is computers

   assert(lobjComputers["один"] == "one");
   foreach (cComputer lobjComputer; lobjComputers) { 
writeln(lobjComputer); }


   /// same output ... these are default properties; gotcha ?

}
```

PS: the above code was typed here but not actually tested


Re: seeking advice: possible new @attribute to mark class' default property to avoid alias this ?

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

On Sunday, 8 August 2021 at 00:52:43 UTC, someone wrote:

Now that I am aware of Walter's stance on alias this:

"alias this has turned out to be a mistake" @ 
https://news.ycombinator.com/item?id=28029184


... would you, I mean the community, think is it a good idea to 
file a DIP to eventually get a new attribute to unambiguously 
label a class' default property ?


Can you please explain what a "default property" is? I have never 
encountered such a thing in any other programming language.


seeking advice: possible new @attribute to mark class' default property to avoid alias this ?

2021-08-07 Thread someone via Digitalmars-d-learn

Now that I am aware of Walter's stance on alias this:

"alias this has turned out to be a mistake" @ 
https://news.ycombinator.com/item?id=28029184


... would you, I mean the community, think is it a good idea to 
file a DIP to eventually get a new attribute to unambiguously 
label a class' default property ?


eg: @default string whatever(...);
eg: @default @property string whatever(...); /// if @property 
survives; that is


... or whatever you consider it should be named ?

Besides, alias this was not implemented to handle default 
properties albeit it seems it is common practice to (as I was 
previously advised to in a previous related post).


Do you think it'll be worth it ?

PS#1: From my unqualified point-of-view it seems it won't be much 
difficult to add it but—I can be quite wrong.


PS#2: I am not using alias this anymore; it is a double-edged 
sword.


Re: array inside a class + alias this + filter -> clears the array.

2021-07-07 Thread realhet via Digitalmars-d-learn

On Wednesday, 7 July 2021 at 17:10:01 UTC, Paul Backus wrote:

On Wednesday, 7 July 2021 at 16:20:29 UTC, realhet wrote:



int[] opIndex() { return array; }


Thx, I didn't know about this type of opSlice override. It works 
nicely.


Now I have these choices:
- write [] everywhere to access the containers.
- write nothing extra to access the containers but put the 
container operations one level higher and select the container 
for those based on a dummy struct.


Like going from:
```
db.entities.add("Entity01");
to
db.add(entity("Entity01"));   //struct entity{ string name; }
```

Currently I have both ways plus your solution for the range 
access.


Gotta experience with it to choose.

Thanks again! I will remember that common container rule from now 
on.


Re: array inside a class + alias this + filter -> clears the array.

2021-07-07 Thread Paul Backus via Digitalmars-d-learn

On Wednesday, 7 July 2021 at 16:20:29 UTC, realhet wrote:

Hi,

I wanted to make a container class that exposes its elements 
using a simple "alias this", but getting weird errors:


I test with the std.algorithm.filter template function.

1. when I use "alias this" on a function that returns a slice, 
making the internal array unreachable, filter just can't 
compile.
2. when I expose the array as it is, filter deletes the array 
after it returns.


My goal is to make a class, which acts like an array, but also 
having member functions to add/remove/find its items. On top of 
that this class has an owner (a database table thing) too.


In general, it is not a good idea to have your container class 
also function as a range, for exactly this reason. Instead, your 
container class should have a method that returns a range over 
its elements, with the range being a separate object.


The conventional way to do this is to overload `opIndex`:

```d
class C
{
private int[] array;
this(int[] array) { this.array = array; }
int[] opIndex() { return array; }
// etc.
}

void main()
{
import std.algorithm;

auto c = new C([1, 2, 3]);
c[].filter!"true".each!writeln;
assert(c[].length == 3);
}
```


array inside a class + alias this + filter -> clears the array.

2021-07-07 Thread realhet via Digitalmars-d-learn

Hi,

I wanted to make a container class that exposes its elements 
using a simple "alias this", but getting weird errors:


I test with the std.algorithm.filter template function.

1. when I use "alias this" on a function that returns a slice, 
making the internal array unreachable, filter just can't compile.
2. when I expose the array as it is, filter deletes the array 
after it returns.


My goal is to make a class, which acts like an array, but also 
having member functions to add/remove/find its items. On top of 
that this class has an owner (a database table thing) too.


Example use-cases:
table.rows.add(...)
table.rows[4]
table.rows.filter!(...).map!(...)


```
import std.stdio, std.range, std.algorithm, std.uni, std.utf, 
std.conv, std.typecons, std.array, std.traits, std.exception, 
std.format, std.random, std.math;


class C{ //must be a class, not a struct
int[] array;

static if(0){
   //BAD: filter cannot deduce from an aliased function
   // that returns a nonref array
  auto getArray(){ return array; }
  alias getArray this;
}else{
  alias array this; //this works
}
}

void main(){
auto c = new C;
c.array = [1, 2];

void wl(){ writeln("len=", c.length); }

//filtering the array explicitly: GOOD
c.array.filter!"true".each!writeln; wl;

//filtering the slice of the alias: GOOD
c.array.filter!"true".each!writeln; wl;

//filtering the alias: BAD -> erases the array
c.filter!"true".each!writeln; wl;
}
```


Thanks in advance.


Re: static alias this and if/do/while/for

2020-10-26 Thread Q. Schroll via Digitalmars-d-learn
On Thursday, 22 October 2020 at 21:55:59 UTC, Jack Applegame 
wrote:

There is a funny feature (or bug) in the D language:

static alias this and static operator overloading.

For example


interface Foo {
static {
int value;
void opAssign(int v) { value = v; }
int get() { return value; }
alias get this;
}
}


Now we can use type Foo as if it were an lvalue/rvalue:


Foo = 5;
int a = Foo;
int b = Foo + a;


I heavily use this feature in my MCU library.


It doesn't surprise me that much. What actually did was that 
static opIndex() works. Consider this:


struct X
{
static int opIndex() { return 1; }
}

alias SliceOf(T) = T[];
enum ValueOf(T) = T[];

static assert( ! is(int[SliceOf!X] == int[ValueOf!X]));

But static opIndex and friends can be useful: 
https://run.dlang.io/is/s15zS0 I'd actually find it awesome if we 
had opCallAssign and opCallOpAssign; the reason I used opIndex 
and not opCall is that way, one gets access to the right-hand 
side and to-assign parameters by reference, so no internal 
pointer stuff's needed.



But it doesn't work inside conditionals:


if(Foo) {}// Error: type Foo is not an expression
while(Foo) {} // Error: type Foo is not an expression


Even if we define `static opCast!bool()`. It doesn't help.


Only using Foo.opCast!bool works; cast(bool) won't compile.


Should this be fixed?


The bool stuff should be fixed. The other direction would be a 
breaking change.


Re: static alias this and if/do/while/for

2020-10-26 Thread Vladimirs Nordholm via Digitalmars-d-learn
On Thursday, 22 October 2020 at 21:55:59 UTC, Jack Applegame 
wrote:

Now we can use type Foo as if it were an lvalue/rvalue:


Foo = 5;
int a = Foo;
int b = Foo + a;


Haha, that's pretty neat!


static alias this and if/do/while/for

2020-10-22 Thread Jack Applegame via Digitalmars-d-learn

There is a funny feature (or bug) in the D language:

static alias this and static operator overloading.

For example


interface Foo {
static {
int value;
void opAssign(int v) { value = v; }
int get() { return value; }
alias get this;
}
}


Now we can use type Foo as if it were an lvalue/rvalue:


Foo = 5;
int a = Foo;
int b = Foo + a;


I heavily use this feature in my MCU library.

But it doesn't work inside conditionals:


if(Foo) {}// Error: type Foo is not an expression
while(Foo) {} // Error: type Foo is not an expression


Even if we define `static opCast!bool()`. It doesn't help.

Should this be fixed?



Re: Subtyping with alias this

2020-08-17 Thread novice3 via Digitalmars-d-learn

On Tuesday, 18 August 2020 at 05:54:16 UTC, H. S. Teoh wrote:

Here's a working example:


Thank you, it works!


Re: Subtyping with alias this

2020-08-17 Thread H. S. Teoh via Digitalmars-d-learn
On Tue, Aug 18, 2020 at 05:34:58AM +, novice3 via Digitalmars-d-learn wrote:
[...]
> The problem is:
> if i use fmt.spec in overloaded toString(),
> when i get error "phobos/std/format.d(2243): Error: no property ip for
> type onlineapp.IpV4Address"

Here's a working example:

-
import std;

struct IpV4Address
{
private uint ip;
alias ip this;

void toString(W,Char)(W sink, FormatSpec!Char fmt)
{
if (fmt.spec == 's') {
// Deal with %s here
sink.formattedWrite("%d.%d.%d.%d",
(ip >> 24) & 0xFF, (ip >> 16) & 0xFF,
(ip >> 8) & 0xFF, ip & 0xFF);
} else {
// Everything else
formatValue(sink, this.ip, fmt);
}
}

// This unittest is to workaround the sillyness that if toString
// doesn't compile, std.format pretends it doesn't exist and/or
// the compiler swallows the real error and substitutes it with
// an irrelevant error that has nothing to do with the real
// problem.
unittest
{
IpV4Address ip;
auto app = appender!string;
ip.toString(app, FormatSpec!char.init);
}
}

unittest
{
auto ip = IpV4Address(0x01020304);
writefln("%s", ip);
writefln("%x", ip);
writefln("%d", ip);
}
-


T

-- 
No! I'm not in denial!


Re: Subtyping with alias this

2020-08-17 Thread novice3 via Digitalmars-d-learn

On Monday, 17 August 2020 at 14:43:27 UTC, H. S. Teoh wrote:
What you need is to create an overload of toString that takes a 
FormatSpec parameter, so that you can decide what should be 
output for which format spec.  Something along these lines:


Sorry, i can't make it works.
I tried ti read format.d, but it too complex for me.

The problem is:
if i use fmt.spec in overloaded toString(),
when i get error "phobos/std/format.d(2243): Error: no property 
ip for type onlineapp.IpV4Address"


reduced code https://run.dlang.io/is/Kgbhfd

```
import std.format;

struct IpV4Address
{
  private uint ip;
  alias ip this;

  void toString(W,Char)(W sink, FormatSpec!Char fmt)
  {
sink(fmt.spec);  // ERROR
//sink("s");   // OK
  }
}
void main()
{
  IpV4Address x;
  assert( format("%s", x) == "s");
}
```
/dlang/dmd-nightly/linux/bin64/../../src/phobos/std/format.d(2243): Error: no 
property ip for type onlineapp.IpV4Address
/dlang/dmd-nightly/linux/bin64/../../src/phobos/std/format.d(1875): Error: 
template instance std.format.formatValueImpl!(Appender!string, IpV4Address, 
char) error instantiating
/dlang/dmd-nightly/linux/bin64/../../src/phobos/std/format.d(576):
instantiated from here: formatValue!(Appender!string, IpV4Address, char)
/dlang/dmd-nightly/linux/bin64/../../src/phobos/std/format.d(6630):
instantiated from here: formattedWrite!(Appender!string, char, IpV4Address)
onlineapp.d(17):instantiated from here: format!(char, 
IpV4Address)




Re: Subtyping with alias this

2020-08-17 Thread H. S. Teoh via Digitalmars-d-learn
On Mon, Aug 17, 2020 at 02:29:47PM +, novice3 via Digitalmars-d-learn wrote:
[...]
> ```
> struct IpV4Address
> {
>   private uint ip;
>   alias ip this;
> 
>   string toString()
>   {
> import std.conv: to;
> return to!string((ip >>> 24) & 0xFF) ~ "." ~
>to!string((ip >>> 16) & 0xFF) ~ "." ~
>to!string((ip >>> 8) & 0xFF) ~ "." ~
>to!string(ip & 0xFF);
>   }

What you need is to create an overload of toString that takes a
FormatSpec parameter, so that you can decide what should be output for
which format spec.  Something along these lines:

string toString(W,Char)(W sink, FormatSpec!Char fmt) {
if (fmt.spec == "s")
return to!string((ip >>> 24) & 0xFF) ~ "." ~
to!string((ip >>> 16) & 0xFF) ~ "." ~
to!string((ip >>> 8) & 0xFF) ~ "." ~
to!string(ip & 0xFF);
else
// Fallback to usual uint-formatting
return format("%s", ip);
}


T

-- 
We've all heard that a million monkeys banging on a million typewriters
will eventually reproduce the entire works of Shakespeare.  Now, thanks
to the Internet, we know this is not true. -- Robert Wilensk


Subtyping with alias this

2020-08-17 Thread novice3 via Digitalmars-d-learn

Hello.
I need subtype uint to store ipv4 address.
It should be like ordinary uint,
except conversion to string with %s format.

My try  https://run.dlang.io/is/fwTc0H  failed on last assert:

```
struct IpV4Address
{
  private uint ip;
  alias ip this;

  string toString()
  {
import std.conv: to;
return to!string((ip >>> 24) & 0xFF) ~ "." ~
   to!string((ip >>> 16) & 0xFF) ~ "." ~
   to!string((ip >>> 8) & 0xFF) ~ "." ~
   to!string(ip & 0xFF);
  }
}
void main()
{
  import std.format: format;
  IpV4Address x;
  x = 0x01020304;  // 1.2.3.4
  assert( x ==  0x01020304 );
  assert( format("%s", x) == "1.2.3.4" );
  assert( format("%x", x) == "01020304" );  // FAILED
  /+
std.format.FormatException@/dlang/dmd-nightly/linux/bin64/../../src/phobos/std/format.d(4065):
 Expected '%s' format specifier for type 'IpV4Address'
  +/
}
```

Is my goal (subtype should be normal uint, but with pretty 
to-string conversion) possible?


Thanks.


Re: I need an Easy example to understand Alias This

2020-07-07 Thread Ferhat Kurtulmuş via Digitalmars-d-learn

On Tuesday, 7 July 2020 at 00:35:38 UTC, Marcone wrote:
Hi, I study Dlang for one year, and I can't understand alias 
this. I need an Easy example to understand Alias This.


I used it for widget inheritance in my experimental code here,

https://github.com/aferust/noobgui/blob/master/source/widget.d


Re: I need an Easy example to understand Alias This

2020-07-07 Thread Cym13 via Digitalmars-d-learn

On Tuesday, 7 July 2020 at 00:44:32 UTC, Marcone wrote:

On Tuesday, 7 July 2020 at 00:42:40 UTC, Ali Çehreli wrote:

On 7/6/20 5:35 PM, Marcone wrote:
Hi, I study Dlang for one year, and I can't understand alias 
this. I need an Easy example to understand Alias This.


Is the following example useful?

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

Ali


I can't undestand it. I need a simple example.


This only scrapes the surface, but it should give an idea of the 
core mechanics and why it's regarded as an important concept.



import std.stdio;

struct Fruit {
string name;
}

struct ColoredFruit {
Fruit _fruit;
alias _fruit this;

string color;
}

void printColoredFruit(ColoredFruit f) {
writeln(f.color, " ", f.name);
}

void printGeneralFruit(Fruit f) {
writeln(f.name);
}

void main(string[] args) {
ColoredFruit banana;
banana.color = "yellow"; // It's a normal struct for its 
non-alias members
banana.name  = "banana"; // We can interact with internal 
fields directly


// This function accepts a ColoredFruit so the whole banana 
is passed.

printColoredFruit(banana);
// > yellow banana

// This function only doesn't accept a ColoredFruit, but it 
does accept a
// Fruit and we have a Fruit alias this so the internal 
_fruit is passed.

printGeneralFruit(banana);
// > banana
}



Re: I need an Easy example to understand Alias This

2020-07-06 Thread Ali Çehreli via Digitalmars-d-learn

On 7/6/20 5:44 PM, Marcone wrote:

On Tuesday, 7 July 2020 at 00:42:40 UTC, Ali Çehreli wrote:

On 7/6/20 5:35 PM, Marcone wrote:
Hi, I study Dlang for one year, and I can't understand alias this. I 
need an Easy example to understand Alias This.


Is the following example useful?

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

Ali


I can't undestand it. I need a simple example.


I find the example of converting two integers to double to be a simple 
example of 'alias this'. (If it's not simple, then there is another 
example later.)


So, allow me to change the name of the struct. :) Let's say we have a 
Money class that stores dollars and cents as two separate members. This 
class also has a member function that returns the amount as double:


struct Money {
  long dollars;
  long cents;

  double value() const {
return double(cents) / 100 + dollars;
  }
}

unittest {
  assert(Money(10, 50).value == 10.5);
}

void main() {
}

So far so good: We can get the value by calling value().

*If* this is a type where conversion to double should be automatic, then 
calling value() all over the place might be considered cumbersome and 
too wordy. If that's true, we may want to get the value of this type 
automatically as double. For example, we may want to be able to call the 
following function with Money:


void foo(double d) {
  // ...
}

void main() {
  foo(Money(20, 50));  // <-- Compilation error
}

Currently the code fails to compile because Money is not 'double'. 
(Note: Arguably, Money is not a type that should be converted to double 
automatically, but again, I find this example simple.)


'alias this' allows a type to be converted to a specific type 
automatically. For example, if we want to convert Money objects 
automatically to 'double', then we use the following line inside the 
struct defition:


  alias value this;

What that line means is this: "Dear compiler, please automatically 
convert this type to whatever the type of the 'value' member is." In 
this case, "Allow using an object of Money wherever that object is used 
in place of a double."


So, with that addition, now the call inside main compiles and foo() gets 
called with 'Money(20, 50).value' (compiler injects an automatic call to 
value()).


Here is the complete program:

struct Money {
  long dollars;
  long cents;

  double value() const {
return double(cents) / 100 + dollars;
  }

  alias value this;  // <-- ADDED
}

unittest {
  assert(Money(10, 50).value == 10.5);
}

void foo(double d) {
  // ...
}

void main() {
  foo(Money(20, 50));
}

'alias this' is sometimes used where a type needs to behave like some 
other type with some added functionality. For example, here is another 
example where a Month type should behave like an 'int' but it cannot 
have any value other than 1-12:


struct Month {
  int value;

  this(int value) {
this.value = value;
  }

  invariant() {
assert(value >= 1);
assert(value <= 12);
  }

  alias value this;
}

unittest {
  import std.exception;

  assertThrown!Error(Month(0));
  assertThrown!Error(Month(13));

  void foo(int) {
  }

  // 'alias this' allows the following call to foo()
  assert(__traits(compiles, foo(Month(3;
}

void main() {
}

Ali



Re: I need an Easy example to understand Alias This

2020-07-06 Thread Ali Çehreli via Digitalmars-d-learn

On 7/6/20 5:35 PM, Marcone wrote:
Hi, I study Dlang for one year, and I can't understand alias this. I 
need an Easy example to understand Alias This.


Is the following example useful?

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

Ali


Re: I need an Easy example to understand Alias This

2020-07-06 Thread Marcone via Digitalmars-d-learn

On Tuesday, 7 July 2020 at 00:42:40 UTC, Ali Çehreli wrote:

On 7/6/20 5:35 PM, Marcone wrote:
Hi, I study Dlang for one year, and I can't understand alias 
this. I need an Easy example to understand Alias This.


Is the following example useful?

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

Ali


I can't undestand it. I need a simple example.


I need an Easy example to understand Alias This

2020-07-06 Thread Marcone via Digitalmars-d-learn
Hi, I study Dlang for one year, and I can't understand alias 
this. I need an Easy example to understand Alias This.


Re: alias this and initialisation

2020-05-25 Thread lalit.singhh via Digitalmars-d-learn

On Monday, 25 May 2020 at 01:35:47 UTC, Danni Coy wrote:

can anybody tell me why

struct S
{
int x;
alias x this;
}

void test()
{
S s;
s = 8; // this works
S s = 8 // but this does not?
}





Re: alias this and initialisation

2020-05-25 Thread Adam D. Ruppe via Digitalmars-d-learn

On Monday, 25 May 2020 at 01:35:47 UTC, Danni Coy wrote:

s = 8; // this works
S s = 8 // but this does not?
}


alias this only applies if you already have an object. 
Construction is too soon.


You can add a constructor to make that work though.


Re: alias this and initialisation

2020-05-25 Thread Ali Çehreli via Digitalmars-d-learn

On 5/24/20 6:35 PM, Danni Coy wrote:> can anybody tell me why
>
> struct S
> {
>  int x;
>  alias x this;
> }
>
> void test()
> {
>  S s;
>  s = 8; // this works
>  S s = 8 // but this does not?
> }

alias this is for implicit conversion, which requires an object to 
convert from. The second case above is about constructing an object.


That's probably why it works that way.

Ali



alias this and initialisation

2020-05-24 Thread Danni Coy via Digitalmars-d-learn
can anybody tell me why

struct S
{
int x;
alias x this;
}

void test()
{
S s;
s = 8; // this works
S s = 8 // but this does not?
}


Re: Trying to alias this a grapheme range + making it a forward range

2019-07-09 Thread aliak via Digitalmars-d-learn

On Monday, 8 July 2019 at 23:01:49 UTC, ag0aep6g wrote:

On 08.07.19 23:55, aliak wrote:

[...]


`source.front` is a temporary `Grapheme` and you're calling 
`opSlice` on it. The documentation for `Grapheme.opSlice` 
warns: "Invalidates when this Grapheme leaves the scope, 
attempts to use it then would lead to memory corruption." [1]


Ah. Right. Thanks!



[...]


hah yes, I realized this as well.



[...]


No you're right. It was indeed just making things more 
complicated and was just a bad idea.




[...]


Cheers,
- Ali


Re: Trying to alias this a grapheme range + making it a forward range

2019-07-08 Thread ag0aep6g via Digitalmars-d-learn

On 08.07.19 23:55, aliak wrote:

struct ustring {
     string data;
     this(string data) {
     this.data = data;
     }
     auto get() {
     static struct Range {
     typeof(string.init.byGrapheme) source;
     bool empty() { return source.empty; }
     void popFront() { source.popFront; }
     auto front() { return source.front[]; }
     auto save() { return this; };
     }
     return Range(this.data.byGrapheme);
     }
     alias get this;
}

But I keep on ending up with a UTFException: "Encoding an invalid code 
point in UTF-8" with code like:


writeln("hello".ustring);


`source.front` is a temporary `Grapheme` and you're calling `opSlice` on 
it. The documentation for `Grapheme.opSlice` warns: "Invalidates when 
this Grapheme leaves the scope, attempts to use it then would lead to 
memory corruption." [1]


So you can't return `source.front[]` from your `front`. You'll have to 
store the current `front` in your struct, I guess.


Also, returning a fresh range on every `alias this` call is asking for 
trouble. This is an infinite loop:


auto u = "hello".ustring;
while (!u.empty) u.popFront();

because `u.empty` and `u.popFront` are called on fresh, non-empty, 
independent ranges.



Problem 2:

How can I get the aliased ustring type to behave as a ForwardRange? If I 
add the save method to the voldermort range type, the 
isForwardRange!ustring fails because the requirement on isForwardRange 
checks to see if save returns the same type it's called on. Which is not 
the case here since typeof(ustring.save) == ustring.get.Range). But 
nontheless does have a save method.


You must provide a `save` that returns a `ustring`. There's no way 
around it.


Maybe make `ustring` itself the range. In the code you've shown, the 
`alias this` only seems to make everything more complicated. But you 
might have good reasons for it, of course.


By the way, your're not calling `source.save` in `Range.save`. You're 
just copying `source`. I don't know if that's effectively the same, and 
even if it is, I'd advise to call `.save` explicitly. Better safe than 
sorry.



[1] https://dlang.org/phobos/std_uni.html#.Grapheme.opSlice


Trying to alias this a grapheme range + making it a forward range

2019-07-08 Thread aliak via Digitalmars-d-learn

Problem 1:

I'm trying to get a string to behave as a .byGrapheme range by 
default, but I can't figure out Grapheme. I'm trying to replicate 
this behavior:


foreach (g; "hello".byGrapheme) {
write(g[]);
}

In a custom type:

struct ustring {
string data;
this(string data) {
this.data = data;
}
auto get() {
static struct Range {
typeof(string.init.byGrapheme) source;
bool empty() { return source.empty; }
void popFront() { source.popFront; }
auto front() { return source.front[]; }
auto save() { return this; };
}
return Range(this.data.byGrapheme);
}
alias get this;
}

But I keep on ending up with a UTFException: "Encoding an invalid 
code point in UTF-8" with code like:


writeln("hello".ustring);

Problem 2:

How can I get the aliased ustring type to behave as a 
ForwardRange? If I add the save method to the voldermort range 
type, the isForwardRange!ustring fails because the requirement on 
isForwardRange checks to see if save returns the same type it's 
called on. Which is not the case here since typeof(ustring.save) 
== ustring.get.Range). But nontheless does have a save method.


Cheers,
- Ali



Re: alias this and struct allocation

2019-05-06 Thread Adam D. Ruppe via Digitalmars-d-learn

On Monday, 6 May 2019 at 14:48:56 UTC, faissaloo wrote:
misunderstood how allocation works when instantiating a struct 
that uses alias this:


alias this has no effect on allocation at all. All it does is if

x.y

doesn't compile, it rewrites it to

x.alias_this.y

(or if f(x) doesn't work, it tries f(x.alias_this) too, same idea 
though.)


That's all it does; it is a way to simplify access to or through 
a member.


So the allocation doesn't factor into it.

Or is base definitely part of the allocation of Child on the 
heap?


It is definitely part of the Child allocation. But if you are 
passing it to a function, keep in mind it still works as a struct.


void foo(Base b) {}

auto child = new Child();

foo(child);


That gets rewritten into

foo(child.base);

which is passed by value there, unlike classes where it is all 
references. So that might be a source of confusion for you.


Re: alias this and struct allocation

2019-05-06 Thread Alex via Digitalmars-d-learn

On Monday, 6 May 2019 at 14:48:56 UTC, faissaloo wrote:
I've been having some memory issues (referenced objects turning 
to nulls for no apparent reason) and I was wondering if I've 
misunderstood how allocation works when instantiating a struct 
that uses alias this:


import std.stdio;

struct Parent {
int a;
}
struct Child {
Parent base;
alias base this;
int y;
}
auto myStructMaker() {
return new Child(Parent(10),20);
}

void main()
{
writeln(*myStructMaker());
}

In this example is the data in base guaranteed to exist?


Yes:
static assert(!__traits(compiles, Child.init.base is null));

Or is base definitely part of the allocation of Child on the 
heap?


I would say, yes. Why do you think it is a contradiction?


Re: alias this and struct allocation

2019-05-06 Thread faissaloo via Digitalmars-d-learn

On Monday, 6 May 2019 at 15:17:37 UTC, aliak wrote:
Do you have an example of a referenced object turning to null? 
We may be able to spot something


Unfortunately I haven't managed to produce an example any smaller 
than my entire codebase


Re: alias this and struct allocation

2019-05-06 Thread aliak via Digitalmars-d-learn

On Monday, 6 May 2019 at 14:48:56 UTC, faissaloo wrote:
I've been having some memory issues (referenced objects turning 
to nulls for no apparent reason) and I was wondering if I've 
misunderstood how allocation works when instantiating a struct 
that uses alias this:


import std.stdio;

struct Parent {
int a;
}
struct Child {
Parent base;
alias base this;
int y;
}
auto myStructMaker() {
return new Child(Parent(10),20);
}

void main()
{
writeln(*myStructMaker());
}

In this example is the data in base guaranteed to exist? Or is 
base definitely part of the allocation of Child on the heap?


Base exists as a value type inside Child so if Child exists, then 
base is definitely there. If base was a class or a pointer to a 
struct, then it may or may not exist.


Here's an excellent post from HS Teoh that explains a lot of 
this: 
https://forum.dlang.org/post/mailman.2535.1417413189.9932.digitalmars-d-le...@puremagic.com


Do you have an example of a referenced object turning to null? We 
may be able to spot something


alias this and struct allocation

2019-05-06 Thread faissaloo via Digitalmars-d-learn
I've been having some memory issues (referenced objects turning 
to nulls for no apparent reason) and I was wondering if I've 
misunderstood how allocation works when instantiating a struct 
that uses alias this:


import std.stdio;

struct Parent {
int a;
}
struct Child {
Parent base;
alias base this;
int y;
}
auto myStructMaker() {
return new Child(Parent(10),20);
}

void main()
{
writeln(*myStructMaker());
}

In this example is the data in base guaranteed to exist? Or is 
base definitely part of the allocation of Child on the heap?


Re: difficulties with const structs and alias this / template functions

2018-11-19 Thread Stanislav Blinov via Digitalmars-d-learn
On Monday, 19 November 2018 at 14:51:14 UTC, Steven Schveighoffer 
wrote:



Or just use inout. This is literally what inout is for:

inout(q32) toQ32 inout {
return q32(x);
}

This should transfer whatever constancy of the original is used 
for the return value.


Yep, I just wanted to explicitly point out the `this T`, which 
gets overlooked way too often.


However, I'd state that this is really a workaround for a 
language deficiency. In reality, I would surmise (without 
knowing the implementation) that q32's state is a complete copy 
of the q16 state. So there is no reason to apply any constancy 
copying from the source to the destination.
The real problem is that mutating operators on struct rvalues 
are always allowed, because `this` is always passed by 
reference. For the most part this is a harmless drawback, but 
because there is no way to "opt out" of this, you can't stop it 
when it really doesn't make sense (as in this case).


Sure. At first I was perplexed why Dennis' a /= 2 even compiled. 
Then I saw the alias this.


I have long wanted a way to direct IFTI how to define its 
parameters base on the arguments. We have a simple adjustment 
for arrays, where the array is always unqual'd before IFTI 
define the parameter.


In other words:

const int[] arr;

void foo(T)(T t) {... }

foo(arr) => T = const(int)[], not const(int[])

I think Andrei in the last dconf proposed we do more of this 
with other types (for ranges, specifically). But I think it 
would be good to also define other conversions possibly 
manually.


I agree completely. Like Dennis' code, or that gcd example from 
Phobos, it'd really help to be able to be explicit in the 
signature, not creative in implementation :) Especially 
considering that Unqual is a high-yield type system nuke.




Re: difficulties with const structs and alias this / template functions

2018-11-19 Thread Stanislav Blinov via Digitalmars-d-learn

On Monday, 19 November 2018 at 14:04:29 UTC, Dennis wrote:
On Monday, 19 November 2018 at 13:34:50 UTC, Stanislav Blinov 
wrote:

Because it's not mutation, it's initialization.


Oh. That's an epiphany for me.


:)

When a ctor is `pure`, the compiler knows it doesn't mutate 
any state other than the object's, so it allows conversion to 
all three qualifiers.


I had trouble thinking of an example where impure constructors 
would break immutable, but now I get it:


```
int* gPtr;

struct S {
  int a;
  this(int a) {
this.a = a;
gPtr = &this.a;
  }
}

void main() {
  S s = 1;
  (*gPtr)++;
}
```
s can't be immutable because its field could be mutated, so the 
constructor needs to be pure (so gPtr can't be set) or 
immutable (so &this.a is an immutable(int)*).


Yep. Or the other way around (as I said earlier, it really makes 
sense when you have indirections inside the struct):


int* global;

struct S {
 const(int)* a;
 this(bool b) {
 if (b) a = global;
 else a = new int;
 }
}

You obviously can't instantiate an immutable S with that ctor, 
since const(int)* may point to mutable data. Nor can you make 
that ctor `pure`. However this is fine:


immutable(int*) global; // note it's an immutable(int*), not an 
immutable(int)*


struct S {
 const(int)* a;
 this(bool b) pure {
 if (b) a = global;
 else a = new int;
 }
}


Re: difficulties with const structs and alias this / template functions

2018-11-19 Thread Steven Schveighoffer via Digitalmars-d-learn

On 11/18/18 1:17 PM, Stanislav Blinov wrote:

On Sunday, 18 November 2018 at 17:30:18 UTC, Dennis wrote:
I'm making a fixed point numeric type and want it to work correctly 
with const. First problem:


```
const q16 a = 6;
a /= 2;  // compiles! despite `a` being const.


Ouch. That's actually kind of nasty.


writeln(a);  // still 6
a.toQ32 /= 2;    // what's actually happening
```

My q16 type has an implicit conversion to q32 (like how int can be 
converted to long):

```
q32 toQ32() const {
  return q32(...);
}
alias toQ32 this;
```
How do I make it so that a const(q16) will be converted to a 
const(q32) instead of mutable q32?


Like this:

     // implement separate methods for mutable/const/immutable
     q32 toQ32() {
     return q32(x);
     }

     const(q32) toQ32() const {
     return q32(x);
     }

     immutable(q32) toQ32() immutable {
     return q32(x);
     }

Or like this:

     // implement all three in one method, using the `this template` 
feature

     auto toQ32(this T)() {
     static if (is(T == immutable))
     return immutable(q32)(x);
     else static if (is(T == const))
     return const(q32)(x);
     else
     return q32(x);
     }


Or just use inout. This is literally what inout is for:

inout(q32) toQ32 inout {
return q32(x);
}

This should transfer whatever constancy of the original is used for the 
return value.


However, I'd state that this is really a workaround for a language 
deficiency. In reality, I would surmise (without knowing the 
implementation) that q32's state is a complete copy of the q16 state. So 
there is no reason to apply any constancy copying from the source to the 
destination.


The real problem is that mutating operators on struct rvalues are always 
allowed, because `this` is always passed by reference. For the most part 
this is a harmless drawback, but because there is no way to "opt out" of 
this, you can't stop it when it really doesn't make sense (as in this case).



Second problem:
```
Q log2(Q)(Q num) if (is(Q : q16) || is(Q : q32)) {
    import std.traits: Unqual;
    Unqual!Q x = num;
    // actual code
}
```
When I call this with a const(q16), Q is resolved to const(q16) so I 
have to unqualify Q every time. It works, but feels clumsy. Is there 
an easier way to automatically de-const parameters? We're working with 
small value types here, it should be simple.


Define different overloads for Q and const Q. Or this:

Q log2(Q)(inout Q num) if (is(Q : q16) || is(Q : q32)) { /* ... */ }

Being able to jam mutable/const/immutable implementation in one function 
like that should tell you that you shouldn't mutate the argument. Then, 
the necessity to Unqual will go away on it's own ;)


I have long wanted a way to direct IFTI how to define its parameters 
base on the arguments. We have a simple adjustment for arrays, where the 
array is always unqual'd before IFTI define the parameter.


In other words:

const int[] arr;

void foo(T)(T t) {... }

foo(arr) => T = const(int)[], not const(int[])

I think Andrei in the last dconf proposed we do more of this with other 
types (for ranges, specifically). But I think it would be good to also 
define other conversions possibly manually.


-Steve


Re: difficulties with const structs and alias this / template functions

2018-11-19 Thread Dennis via Digitalmars-d-learn
On Monday, 19 November 2018 at 13:34:50 UTC, Stanislav Blinov 
wrote:

Because it's not mutation, it's initialization.


Oh. That's an epiphany for me.

When a ctor is `pure`, the compiler knows it doesn't mutate any 
state other than the object's, so it allows conversion to all 
three qualifiers.


I had trouble thinking of an example where impure constructors 
would break immutable, but now I get it:


```
int* gPtr;

struct S {
  int a;
  this(int a) {
this.a = a;
gPtr = &this.a;
  }
}

void main() {
  S s = 1;
  (*gPtr)++;
}
```
s can't be immutable because its field could be mutated, so the 
constructor needs to be pure (so gPtr can't be set) or immutable 
(so &this.a is an immutable(int)*).


What you can do, however, if you don't have an const/immutable 
constructor, is call a mutable constructor explicitly, so long 
as conversion is possible (i.e. value types)


Interesting.




Re: difficulties with const structs and alias this / template functions

2018-11-19 Thread Stanislav Blinov via Digitalmars-d-learn

On Monday, 19 November 2018 at 12:28:43 UTC, Dennis wrote:
On Monday, 19 November 2018 at 02:39:32 UTC, Stanislav Blinov 
wrote:

You're skimming the examples ;)


I'm not saying your examples don't work, I'm trying to 
understand the minimum requirements. You said:


"That's [constructors needing to be pure is] only for types 
with indirections (pointers), since `pure` guarantees that you 
do not mutate any global state."


My example was only to show that:
- a const constructor is insufficient for creating an immutable 
struct S
- an immutable or pure constructor is sufficient for creating 
an immutable struct S


Yes, that's what I meant.


You also showed that an inout constructor is sufficient too.

I don't understand why not any constructor would work. After 
all:


"value types are all copyable between mutable/const/immutable. 
So even if `return x + y` would yield a `const T`, you can 
still instantiate a T from it."


Because the rules still hold:

this(int) -> __ctor(T, int);
this(int) const -> __ctor(const T, int);
this(int) immutable -> __ctor(immutable T, int);

Recall that member functions (including constructors) are just 
functions in disguise:

...
what that boils down to, conceptually, is:


I get what inout does know. But continuing on the constructor 
lowering, what strikes me is that:


S __ctor(ref const S this, int x) {
this.x = x; // allowed, while `this` is a const(S)!
// return this; automatically inserted
}

Knowing that a constructor may mutate the const(this) or 
immutable(this) members, why can't a mutable(this) constructor 
be called on an immutable(this), *unless* it is pure (which 
seems irrelevant to me)?


Because it's not mutation, it's initialization. Just like you 
write:


const int x = 1; // initializes a const int
x = 10; // error, can't mutate

...the first assignment to a member in a constructor is 
initialization:


struct S {
int x;
this(int x) immutable {
this.x = x; // ok, initialization
this.x = 5; // error, can't mutate
}
}

When a ctor is `pure`, the compiler knows it doesn't mutate any 
state other than the object's, so it allows conversion to all 
three qualifiers.


What you can do, however, if you don't have an const/immutable 
constructor, is call a mutable constructor explicitly, so long as 
conversion is possible (i.e. value types):


struct S {
this(int) /* not immutable */ {}
}

immutable S x = 1; // error
immutable S x = S(1); // ok


Re: difficulties with const structs and alias this / template functions

2018-11-19 Thread Dennis via Digitalmars-d-learn
On Monday, 19 November 2018 at 02:39:32 UTC, Stanislav Blinov 
wrote:

You're skimming the examples ;)


I'm not saying your examples don't work, I'm trying to understand 
the minimum requirements. You said:


"That's [constructors needing to be pure is] only for types with 
indirections (pointers), since `pure` guarantees that you do not 
mutate any global state."


My example was only to show that:
- a const constructor is insufficient for creating an immutable 
struct S
- an immutable or pure constructor is sufficient for creating an 
immutable struct S


You also showed that an inout constructor is sufficient too.

I don't understand why not any constructor would work. After all:

"value types are all copyable between mutable/const/immutable. So 
even if `return x + y` would yield a `const T`, you can still 
instantiate a T from it."


Recall that member functions (including constructors) are just 
functions in disguise:

...
what that boils down to, conceptually, is:


I get what inout does know. But continuing on the constructor 
lowering, what strikes me is that:


S __ctor(ref const S this, int x) {
this.x = x; // allowed, while `this` is a const(S)!
// return this; automatically inserted
}

Knowing that a constructor may mutate the const(this) or 
immutable(this) members, why can't a mutable(this) constructor be 
called on an immutable(this), *unless* it is pure (which seems 
irrelevant to me)?


Re: difficulties with const structs and alias this / template functions

2018-11-18 Thread Stanislav Blinov via Digitalmars-d-learn

On Monday, 19 November 2018 at 02:08:14 UTC, Dennis wrote:
On Monday, 19 November 2018 at 01:24:02 UTC, Stanislav Blinov 
wrote:
Yup, that's because, like Rubn said, copying value types is 
trivial. Where it all comes to bite you is when you start 
having pointers, because you can't copy a const(T)* into a T*.


I'm not using reference types, but still:

```
struct S {
int a;
this(int a) {
this.a = a;
}
}

void main()
{
immutable S d = 3;
}

```

onlineapp.d(10): Error: mutable method onlineapp.S.this is not 
callable using a immutable object
onlineapp.d(10):Consider adding const or inout to 
onlineapp.S.this


const still leaves the first error...


You're skimming the examples ;)

struct S {
int a;
this(int a) { this.a = a; }
this(int a) const { this.a = a; }
this(int a) immutable { this.a = a; }
}

or

struct S {
int a;
this(this T)(int a) { this.a = a; }
}


...inout works though I don't know what it does.


Recall that member functions (including constructors) are just 
functions in disguise:


struct S {
this(int a) inout { /* ... */ }
}

what that boils down to, conceptually, is:

void _compiler_made_it_a_struct_S_constructor(ref inout S this, 
int a);


In other words, an `inout` method makes the "this" reference an 
`inout`. Same goes for const, immutable, etc.


Re: difficulties with const structs and alias this / template functions

2018-11-18 Thread Stanislav Blinov via Digitalmars-d-learn

On Monday, 19 November 2018 at 02:03:18 UTC, Dennis wrote:
On Monday, 19 November 2018 at 01:13:29 UTC, Stanislav Blinov 
wrote:

You just dismissed that second to last sentence, did you? :)


I don't know what you mean with it. It's not that I'm trying to 
be sneaky or lazy really trying to modify the const parameter 
when I should treat it properly. And as the author I'm fine 
with Unqualing everything if that's needed, my concern is when 
another person using my type tries to write his own function:


```
q16 pow(q16 base, int exponent) {
  q16 result = 1;
  foreach(i; 0..exponent) result *= base;
  return result;
}

const q16 x = 3;
writeln(pow(x, 3)); //works!
```

He then wants to make it more generic, so he rewrites:

```
Q pow(Q base, int exponent) if (isFixedPoint!Q) {
  Q result = 1;
  foreach(i; 0..exponent) result *= base;
  return result;
}
```

And initially it seems to work, but as soon as it is used with 
const it breaks as `result` can't be mutated anymore.


Yes, but that's not the problem with your type. It's a problem 
with the user not realizing that const is a type qualifier.


I'd like to set the example of writing proper generic 
functions, and if there is something simpler than importing 
Unqual I'd prefer that over my current solution. If there 
isn't, I'll just need to write a "don't forget to Unqual const" 
comment.



```
T f0(T)(inout T x, inout T y) { return x + y; }
```

;)


What does inout do here?


You're right, it's not needed there at all.

If the return type is also inout(T) I know that the return type 
gets the same qualifiers as inout parameters. But in this 
example, the return value is still T.


Because, as before, value types are all copyable between 
mutable/const/immutable. So even if `return x + y` would yield a 
`const T`, you can still instantiate a T from it.




Re: difficulties with const structs and alias this / template functions

2018-11-18 Thread Dennis via Digitalmars-d-learn
On Monday, 19 November 2018 at 01:24:02 UTC, Stanislav Blinov 
wrote:
Yup, that's because, like Rubn said, copying value types is 
trivial. Where it all comes to bite you is when you start 
having pointers, because you can't copy a const(T)* into a T*.


I'm not using reference types, but still:

```
struct S {
int a;
this(int a) {
this.a = a;
}
}

void main()
{
immutable S d = 3;
}

```

onlineapp.d(10): Error: mutable method onlineapp.S.this is not 
callable using a immutable object
onlineapp.d(10):Consider adding const or inout to 
onlineapp.S.this


const still leaves the first error, inout works though I don't 
know what it does.

Adding pure also works.


Re: difficulties with const structs and alias this / template functions

2018-11-18 Thread Dennis via Digitalmars-d-learn
On Monday, 19 November 2018 at 01:13:29 UTC, Stanislav Blinov 
wrote:

You just dismissed that second to last sentence, did you? :)


I don't know what you mean with it. It's not that I'm trying to 
be sneaky or lazy really trying to modify the const parameter 
when I should treat it properly. And as the author I'm fine with 
Unqualing everything if that's needed, my concern is when another 
person using my type tries to write his own function:


```
q16 pow(q16 base, int exponent) {
  q16 result = 1;
  foreach(i; 0..exponent) result *= base;
  return result;
}

const q16 x = 3;
writeln(pow(x, 3)); //works!
```

He then wants to make it more generic, so he rewrites:

```
Q pow(Q base, int exponent) if (isFixedPoint!Q) {
  Q result = 1;
  foreach(i; 0..exponent) result *= base;
  return result;
}
```

And initially it seems to work, but as soon as it is used with 
const it breaks as `result` can't be mutated anymore. I'd like to 
set the example of writing proper generic functions, and if there 
is something simpler than importing Unqual I'd prefer that over 
my current solution. If there isn't, I'll just need to write a 
"don't forget to Unqual const" comment.



```
T f0(T)(inout T x, inout T y) { return x + y; }
```

;)


What does inout do here? If the return type is also inout(T) I 
know that the return type gets the same qualifiers as inout 
parameters. But in this example, the return value is still T.


I know it's a bit painful though. In fact, Phobos also suffers 
from it. In std.numeric:


Yuck!



Re: difficulties with const structs and alias this / template functions

2018-11-18 Thread Stanislav Blinov via Digitalmars-d-learn

On Monday, 19 November 2018 at 00:50:28 UTC, Dennis wrote:

I'm also trying to make it work with immutable, and from BigInt 
[2] I learned that constructors need to be `pure` for creating 
immutable objects. (I don't know why.)


That's only for types with indirections (pointers), since `pure` 
guarantees that you do not mutate any global state.


For value types, they work just fine:

struct q16 {
uint x;

this(uint x) { this.x = x; }
this(uint x) const { this.x = x; }
this(uint x) immutable { this.x = x; }

// or again, all three packed together:

this(this T)(uint x) { this.x = x; }
}

Are there any other gotchas? I didn't add an immutable variant 
for toQ32 like Stanislav suggested, but creating an immutable 
q32 from a q16 still seems to work fine.


Yup, that's because, like Rubn said, copying value types is 
trivial. Where it all comes to bite you is when you start having 
pointers, because you can't copy a const(T)* into a T*.




Re: difficulties with const structs and alias this / template functions

2018-11-18 Thread Stanislav Blinov via Digitalmars-d-learn

On Sunday, 18 November 2018 at 20:10:52 UTC, Dennis wrote:
On Sunday, 18 November 2018 at 18:17:54 UTC, Stanislav Blinov 
wrote:


Q log2(Q)(inout Q num) if (is(Q : q16) || is(Q : q32)) { /* 
... */ }


Being able to jam mutable/const/immutable implementation in 
one function like that should tell you that you shouldn't 
mutate the argument. Then, the necessity to Unqual will go 
away on it's own ;)


Different overloads sounds like a lot of boilerplate.
inout still results in "cannot modify `inout` expression 
`input`"


You just dismissed that second to last sentence, did you? :)

My goal is to be able to write straightforward and correct 
signatures for fixed point functions that receive mutable 
copies of whatever they are fed. This isn't even limited to my 
custom types:


```
T f0(T)(T x, T y) {return x += y;}
int  f1(int  x, int  y) {return x += y;}
long f1(long x, long y) {return x += y;}
```
The explicit overloads of f1 work fine, but the generic f0 does 
not.


```
T f0(T)(inout T x, inout T y) { return x + y; }
```

;)

But if you really really want to mutate the argument, then 
handling different mutability for T is the only way:


```
T f0(T)(T x, T y) {
import std.traits : isMutable;
static if (isMutable!T) return x += y;
else return x + y;
}
```

I know it's a bit painful though. In fact, Phobos also suffers 
from it. In std.numeric:


T gcd(T)(T a, T b)
if (isIntegral!T)
{
static if (is(T == const) || is(T == immutable))
{
return gcd!(Unqual!T)(a, b);
}
// ...
}

Not only that looks ugly, but (with DMD) it makes gcd a doulbe 
function call :D


Re: difficulties with const structs and alias this / template functions

2018-11-18 Thread Dennis via Digitalmars-d-learn

On Sunday, 18 November 2018 at 22:30:52 UTC, Rubn wrote:
Yah most people tend to avoid const for this reason. It only 
really works for basic types, if you have a "const int" you can 
convert it to an "int" by copy. But if you have a type like 
Vector!(const int) that won't work, you can't even convert 
Vector!int to Vector!(const int) easily for example.


That's unfortunate. I can relate better to Jonathan's article [1] 
now. But I'll still try to make it working with const since other 
people might want to use it.


I'm also trying to make it work with immutable, and from BigInt 
[2] I learned that constructors need to be `pure` for creating 
immutable objects. (I don't know why.)


Are there any other gotchas? I didn't add an immutable variant 
for toQ32 like Stanislav suggested, but creating an immutable q32 
from a q16 still seems to work fine.


[1] http://jmdavisprog.com/articles/why-const-sucks.html
[2] https://issues.dlang.org/show_bug.cgi?id=17330


Re: difficulties with const structs and alias this / template functions

2018-11-18 Thread Rubn via Digitalmars-d-learn

On Sunday, 18 November 2018 at 17:30:18 UTC, Dennis wrote:
I'm making a fixed point numeric type and want it to work 
correctly with const. First problem:


```
const q16 a = 6;
a /= 2;  // compiles! despite `a` being const.
writeln(a);  // still 6
a.toQ32 /= 2;// what's actually happening
```

My q16 type has an implicit conversion to q32 (like how int can 
be converted to long):

```
q32 toQ32() const {
  return q32(...);
}
alias toQ32 this;
```
How do I make it so that a const(q16) will be converted to a 
const(q32) instead of mutable q32?


Second problem:
```
Q log2(Q)(Q num) if (is(Q : q16) || is(Q : q32)) {
import std.traits: Unqual;
Unqual!Q x = num;
// actual code
}
```
When I call this with a const(q16), Q is resolved to const(q16) 
so I have to unqualify Q every time. It works, but feels 
clumsy. Is there an easier way to automatically de-const 
parameters? We're working with small value types here, it 
should be simple.


If anyone knows any other pitfalls with const, I'd love to know 
them.


Yah most people tend to avoid const for this reason. It only 
really works for basic types, if you have a "const int" you can 
convert it to an "int" by copy. But if you have a type like 
Vector!(const int) that won't work, you can't even convert 
Vector!int to Vector!(const int) easily for example.



```
Q log2(Q)(Q num) if (is(Q : q16) || is(Q : q32)) {
import std.traits: Unqual;
Unqual!Q x = num;
// actual code
}
```


This is pretty much the only way, you can just add

alias V = Unqual!Q;

then use V in your function instead of Unqual!Q everywhere.


Re: difficulties with const structs and alias this / template functions

2018-11-18 Thread Dennis via Digitalmars-d-learn
On Sunday, 18 November 2018 at 18:17:54 UTC, Stanislav Blinov 
wrote:
// implement separate methods for 
mutable/const/immutable


Thanks. I should have tried that, but I assumed it wouldn't work 
since you can't overload on return-type only. However, the const 
/ non-const makes it allowed.



Or like this:

// implement all three in one method, using the `this 
template` feature


That's new to me, interesting.


Define different overloads for Q and const Q. Or this:

Q log2(Q)(inout Q num) if (is(Q : q16) || is(Q : q32)) { /* ... 
*/ }


Being able to jam mutable/const/immutable implementation in one 
function like that should tell you that you shouldn't mutate 
the argument. Then, the necessity to Unqual will go away on 
it's own ;)


Different overloads sounds like a lot of boilerplate.
inout still results in "cannot modify `inout` expression `input`"
My goal is to be able to write straightforward and correct 
signatures for fixed point functions that receive mutable copies 
of whatever they are fed. This isn't even limited to my custom 
types:


```
T f0(T)(T x, T y) {return x += y;}
int  f1(int  x, int  y) {return x += y;}
long f1(long x, long y) {return x += y;}

void main()
{
import std.stdio;
writeln(f0(const(int)(3), const(long)(4))); // can't modify 
const

writeln(f1(const(int)(3), const(long)(4))); // fine
}
```
The explicit overloads of f1 work fine, but the generic f0 does 
not. I could just use the f1 strategy of explicitly making 
overloads, but then adding a q64 or q128 type would mean having 
to double the existing boilerplate everywhere. I would like to 
have a `isFixedPoint` template and generic functions that take 
any isFixedPoint!Q, but it seems I have to manually enforce 
"don't forget to unqual Q first!".




Re: difficulties with const structs and alias this / template functions

2018-11-18 Thread Stanislav Blinov via Digitalmars-d-learn

On Sunday, 18 November 2018 at 17:30:18 UTC, Dennis wrote:
I'm making a fixed point numeric type and want it to work 
correctly with const. First problem:


```
const q16 a = 6;
a /= 2;  // compiles! despite `a` being const.


Ouch. That's actually kind of nasty.


writeln(a);  // still 6
a.toQ32 /= 2;// what's actually happening
```

My q16 type has an implicit conversion to q32 (like how int can 
be converted to long):

```
q32 toQ32() const {
  return q32(...);
}
alias toQ32 this;
```
How do I make it so that a const(q16) will be converted to a 
const(q32) instead of mutable q32?


Like this:

// implement separate methods for mutable/const/immutable
q32 toQ32() {
return q32(x);
}

const(q32) toQ32() const {
return q32(x);
}

immutable(q32) toQ32() immutable {
return q32(x);
}

Or like this:

// implement all three in one method, using the `this 
template` feature

auto toQ32(this T)() {
static if (is(T == immutable))
return immutable(q32)(x);
else static if (is(T == const))
return const(q32)(x);
else
return q32(x);
}



Second problem:
```
Q log2(Q)(Q num) if (is(Q : q16) || is(Q : q32)) {
import std.traits: Unqual;
Unqual!Q x = num;
// actual code
}
```
When I call this with a const(q16), Q is resolved to const(q16) 
so I have to unqualify Q every time. It works, but feels 
clumsy. Is there an easier way to automatically de-const 
parameters? We're working with small value types here, it 
should be simple.


Define different overloads for Q and const Q. Or this:

Q log2(Q)(inout Q num) if (is(Q : q16) || is(Q : q32)) { /* ... 
*/ }


Being able to jam mutable/const/immutable implementation in one 
function like that should tell you that you shouldn't mutate the 
argument. Then, the necessity to Unqual will go away on it's own 
;)


difficulties with const structs and alias this / template functions

2018-11-18 Thread Dennis via Digitalmars-d-learn
I'm making a fixed point numeric type and want it to work 
correctly with const. First problem:


```
const q16 a = 6;
a /= 2;  // compiles! despite `a` being const.
writeln(a);  // still 6
a.toQ32 /= 2;// what's actually happening
```

My q16 type has an implicit conversion to q32 (like how int can 
be converted to long):

```
q32 toQ32() const {
  return q32(...);
}
alias toQ32 this;
```
How do I make it so that a const(q16) will be converted to a 
const(q32) instead of mutable q32?


Second problem:
```
Q log2(Q)(Q num) if (is(Q : q16) || is(Q : q32)) {
import std.traits: Unqual;
Unqual!Q x = num;
// actual code
}
```
When I call this with a const(q16), Q is resolved to const(q16) 
so I have to unqualify Q every time. It works, but feels clumsy. 
Is there an easier way to automatically de-const parameters? 
We're working with small value types here, it should be simple.


If anyone knows any other pitfalls with const, I'd love to know 
them.


Re: How can I induce implicit type convesion with alias this on calling template function?

2018-10-15 Thread Sobaya via Digitalmars-d-learn

On Monday, 15 October 2018 at 06:16:34 UTC, Alex wrote:

On Monday, 15 October 2018 at 04:51:39 UTC, Sobaya wrote:

[...]


Removing constraint, but retaining specialization should be 
enough, no?
Then, func is still a template, requiring the argument to be 
convertible to an int. When S is passed, then, it is checked, 
if it convertible, and because of the alias it is.
Still, passed value has the type of S. however, func can handle 
value directly, as it were an int.


Thank you!


Re: How can I induce implicit type convesion with alias this on calling template function?

2018-10-14 Thread Alex via Digitalmars-d-learn

On Monday, 15 October 2018 at 04:51:39 UTC, Sobaya wrote:

void func(T : int)(T value) if (is(T == int)) {
}

struct S {
int x;
alias x this;
}

void main() {
func(S()); // error
}

In above code, 'func' can accept only int as its argument type, 
so when 'S', which can be implicitly convertible into int, is 
passed on 'func', I expect S.x is passed, but this function 
call is failed.


Is there any way to solve it with keeping 'func' template 
function?


Removing constraint, but retaining specialization should be 
enough, no?
Then, func is still a template, requiring the argument to be 
convertible to an int. When S is passed, then, it is checked, if 
it convertible, and because of the alias it is.
Still, passed value has the type of S. however, func can handle 
value directly, as it were an int.




How can I induce implicit type convesion with alias this on calling template function?

2018-10-14 Thread Sobaya via Digitalmars-d-learn

void func(T : int)(T value) if (is(T == int)) {
}

struct S {
int x;
alias x this;
}

void main() {
func(S()); // error
}

In above code, 'func' can accept only int as its argument type, 
so when 'S', which can be implicitly convertible into int, is 
passed on 'func', I expect S.x is passed, but this function call 
is failed.


Is there any way to solve it with keeping 'func' template 
function?




Re: Alias this and opDispatch override

2018-09-06 Thread Domain via Digitalmars-d-learn

On Friday, 7 September 2018 at 02:22:58 UTC, Domain wrote:

The following code fail to compile:

enum KeyMod : int
{
LCtrl  = 1 << 0,
RCtrl  = 1 << 1,
Ctrl   = LCtrl | RCtrl,
}

struct Flags(E)
{
public:
BitFlags!(E, Yes.unsafe) flags;
alias flags this;

bool opDispatch(string name)() const
if (__traits(hasMember, E, name))
{
enum e = __traits(getMember, E, name);
return (mValue & e) != 0;
}
}

Flags!KeyMod keys;
keys.LCtrl = true;
assert(keys.Ctrl);

Error: no property LCtrl for type Flags!(KeyMod)
Error: no property Ctrl for type Flags!(KeyMod)


Sorry. This works:

struct Flags(E)
{
public:
BitFlags!(E, Yes.unsafe) flags;
alias flags this;

bool opDispatch(string name)() const
if (__traits(hasMember, E, name))
{
enum e = __traits(getMember, E, name);
return cast(int)(flags & e) != 0;
}

void opDispatch(string name)(bool set)
if (__traits(hasMember, E, name))
{
enum e = __traits(getMember, E, name);
if (set)
flags |= e;
else
flags &= ~e;
}
}


Alias this and opDispatch override

2018-09-06 Thread Domain via Digitalmars-d-learn

The following code fail to compile:

enum KeyMod : int
{
LCtrl  = 1 << 0,
RCtrl  = 1 << 1,
Ctrl   = LCtrl | RCtrl,
}

struct Flags(E)
{
public:
BitFlags!(E, Yes.unsafe) flags;
alias flags this;

bool opDispatch(string name)() const
if (__traits(hasMember, E, name))
{
enum e = __traits(getMember, E, name);
return (mValue & e) != 0;
}
}

Flags!KeyMod keys;
keys.LCtrl = true;
assert(keys.Ctrl);

Error: no property LCtrl for type Flags!(KeyMod)
Error: no property Ctrl for type Flags!(KeyMod)


Re: Question about template argument matching with alias this

2018-07-30 Thread Alex via Digitalmars-d-learn

On Sunday, 29 July 2018 at 23:03:27 UTC, Johannes Loher wrote:
Yeah, I know that it possible to implement the template like 
this, but that is not the point here. I would like to know why 
it does not work the way I described it. To me it seems very 
strange, that `S : T` has different semantics in `is` 
expressions and as template parameters.




Yes... I see your point now. It is like "is" itself adds some 
semantics to the colon operator. So, while colon specifies, that 
only derivatives are matched, "is" matches all things, where the 
interface can be extracted...


I think, this is intended:
https://dlang.org/spec/template.html#argument_deductionp. 5
and
https://dlang.org/spec/expression.html#is_expressionp. 2

But... maybe some native D speaker could comment on this...

Now I could ask the author of poodinis to remove the 
restriction on the template parameters for register, but it 
actually perfectly makes sense to have that restriction, 
because we are registering a concrete type as an abstract type.


I would say, for practical reasons not to remove the restriction, 
but to formulate it in a more abstract way. This seems to be with 
´if(is(S : T))´ in this case... As otherwise the restriction is 
to use classes only... (?)


So I am back to my question: Why do we have this strange 
behavior? All compiler version on run.dlang.io behave like 
that, so I suppose there is some reason for this...?


Re: Question about template argument matching with alias this

2018-07-29 Thread Johannes Loher via Digitalmars-d-learn

On Sunday, 29 July 2018 at 20:51:45 UTC, Alex wrote:

Do you mean something like this?
[...]


Yeah, I know that it possible to implement the template like 
this, but that is not the point here. I would like to know why it 
does not work the way I described it. To me it seems very 
strange, that `S : T` has different semantics in `is` expressions 
and as template parameters.


My actual problem is the following: I would like to use the 
dependency injection framework poodinis [1] in conjuction with 
the mocking capabilities from unit-threaded [2]. My code would 
look something like the following:


```
import poodinis : DependencyContainer;
import unit_threaded.mock : mock;

interface SomeInterface
{
}

unittest
{
auto myMock = mock!SomeInterface;
alias MockedType = typeof(myMock)
auto container = new shared DependencyContainer;

container.register!(SomeInterface, 
MockedType)().existingInstance(myMock);

/* ... */
}
```

The problem with this is that register has the signature 
described above, i.e. register(T, S : T)() and that the mock 
template from unit-threaded is actually implemented by a struct 
which is "alias this"ed (how do you call that...? :D) to a class 
which is derived from the mocked interface. This means I run 
exactly into the problem I described in the first post.


Now I could ask the author of poodinis to remove the restriction 
on the template parameters for register, but it actually 
perfectly makes sense to have that restriction, because we are 
registering a concrete type as an abstract type.


I also had a quick look at the implementation of mock, which 
seems to be quite complicated already. So I fear that changing 
this implementation to using a derived class directly is unlikely 
to happen.


So I am back to my question: Why do we have this strange 
behavior? All compiler version on run.dlang.io behave like that, 
so I suppose there is some reason for this...?


[0] https://github.com/mbierlee/poodinis
[1] https://github.com/atilaneves/unit-threaded


Re: Question about template argument matching with alias this

2018-07-29 Thread Alex via Digitalmars-d-learn

On Sunday, 29 July 2018 at 16:43:08 UTC, Johannes Loher wrote:
I have a question about template argument matching in 
combination with implicit conversion and alias this. Consider 
the following code:



interface SomeInterface
{
}

class SomeClass : SomeInterface
{
}

struct SomeStruct
{
SomeClass someClass;
alias someClass this;
}

template isSuperType(T, S : T)
{
enum isSuperType = is(SomeStruct : SomeInterface);
}

void main()
{
static assert(is(SomeStruct : SomeInterface));
static assert(isSuperType!(SomeInterface, SomeStruct)); // 
why does the template not match?

}


The question is, why does the template declaration not match? 
Thanks for your help!


Do you mean something like this?

´´´
interface SomeInterface {}

class SomeClass : SomeInterface {}

struct SomeStruct
{
SomeClass someClass;
alias someClass this;
}

template isSuperType(T, S) if(is(S : T))
{
enum isSuperType = is(S : T);
}

static assert(is(SomeStruct : SomeInterface));
static assert(isSuperType!(SomeInterface, SomeStruct));
void main(){}
´´´


Question about template argument matching with alias this

2018-07-29 Thread Johannes Loher via Digitalmars-d-learn
I have a question about template argument matching in combination 
with implicit conversion and alias this. Consider the following 
code:



interface SomeInterface
{
}

class SomeClass : SomeInterface
{
}

struct SomeStruct
{
SomeClass someClass;
alias someClass this;
}

template isSuperType(T, S : T)
{
enum isSuperType = is(SomeStruct : SomeInterface);
}

void main()
{
static assert(is(SomeStruct : SomeInterface));
static assert(isSuperType!(SomeInterface, SomeStruct)); // 
why does the template not match?

}


The question is, why does the template declaration not match? 
Thanks for your help!


Re: Functor alias this

2018-06-05 Thread Simen Kjærås via Digitalmars-d-learn

On Wednesday, 6 June 2018 at 06:25:49 UTC, DaggetJones wrote:
Hi, I'm wondering how I should approach supplying 
functions/delegates around in D. I have option of using classes 
where the function exists inside the class and to provide 
different functionality different classes are created.
Alternatively I could just pass the function directly around 
without all the weight of the class.


This led me to wonder if there is a way to combine the two 
methods?



With D's alias this would it be possible to have the user code 
treat the function as a delegate but define the functions 
actually in a class without any restrictions?



import std.stdio;

alias MyFunction = int delegate();

class MyFunctor
{
   alias func this;
   int MyData = 5;
   int func() { return MyData; }
}



void bar(MyFunction foo) { writeln(foo()); }

void main()
{

MyFunctor f = new MyFunctor();

bar(&f.func);
// but not
// bar(f); or bar(&f);

}


But I would like to simply pass the class as if it were the 
member func, which is what the alias this is suppose to provide.


It seems D ignores the alias this in this case?


You'll need to provide a function that returns func. The way it's 
currently written, the alias this would basically translate to 
bar(f.func()):


class MyFunctor
{
   alias func2 this;
   int MyData = 5;
   int func() { return MyData; }
   auto func2() { return &func; }
}

--
  Simen


Functor alias this

2018-06-05 Thread DaggetJones via Digitalmars-d-learn
Hi, I'm wondering how I should approach supplying 
functions/delegates around in D. I have option of using classes 
where the function exists inside the class and to provide 
different functionality different classes are created.
Alternatively I could just pass the function directly around 
without all the weight of the class.


This led me to wonder if there is a way to combine the two 
methods?



With D's alias this would it be possible to have the user code 
treat the function as a delegate but define the functions 
actually in a class without any restrictions?



import std.stdio;

alias MyFunction = int delegate();

class MyFunctor
{
   alias func this;
   int MyData = 5;
   int func() { return MyData; }
}



void bar(MyFunction foo) { writeln(foo()); }

void main()
{

MyFunctor f = new MyFunctor();

bar(&f.func);
// but not
// bar(f); or bar(&f);

}


But I would like to simply pass the class as if it were the 
member func, which is what the alias this is suppose to provide.


It seems D ignores the alias this in this case?





Re: Get the type of 'alias this ='

2018-04-04 Thread Vladimirs Nordholm via Digitalmars-d-learn

On Wednesday, 4 April 2018 at 15:57:19 UTC, Simen Kjærås wrote:
On Wednesday, 4 April 2018 at 15:49:31 UTC, Vladimirs Nordholm 
wrote:

if (is(T == A) || is(T == B) || is(T == Enum))


if (is(T : Enum))

--
  Simen


Ah! Thanks a lot!


Re: Get the type of 'alias this ='

2018-04-04 Thread Vladimirs Nordholm via Digitalmars-d-learn
On Wednesday, 4 April 2018 at 15:49:31 UTC, Vladimirs Nordholm 
wrote:

private template Mix()
{
this(Enum ee) { e = ee; }
Enum e;
alias this = e;
}



Oops, typo in the alias. Should be `alias e this`


Re: Get the type of 'alias this ='

2018-04-04 Thread Simen Kjærås via Digitalmars-d-learn
On Wednesday, 4 April 2018 at 15:49:31 UTC, Vladimirs Nordholm 
wrote:

if (is(T == A) || is(T == B) || is(T == Enum))


if (is(T : Enum))

--
  Simen


Get the type of 'alias this ='

2018-04-04 Thread Vladimirs Nordholm via Digitalmars-d-learn

Hello people from D-land.

Short question: Can get the type of a struct that has `alias this 
= ` ?


See this example, where a struct is aliased to an enum:


enum Enum { one, two, three, fourtytwo }

private template Mix()
{
this(Enum ee) { e = ee; }
Enum e;
alias this = e;
}
struct A { mixin Mix }
struct B { mixin Mix }

T foo(T) (T f) if (is(T == A) || is(T == B) || is(T == Enum))
//   |--|
// ^ I want to change this into 
something more nice looking

{
// ...
}


I want to check the type in a more 'cleaner' way.

Best regards,
Vladimirs Nordholm


Re: Trying to forward unwrapped opDispatch names to alias this

2018-02-20 Thread aliak via Digitalmars-d-learn

On Tuesday, 20 February 2018 at 16:12:17 UTC, Adam D. Ruppe wrote:

On Monday, 19 February 2018 at 08:28:22 UTC, aliak wrote:
T is the wrapped type. So if T has a member (in the example 
it's the built in field "max") then forward that.


Oh, I see what you mean.

So the problem is that built in types don't have "members" per 
se, they have "magic". The built in properties don't count to 
`hasMember`. You could probably do `if(__traits(compiles, 
mixin("a." ~ member))` though.


I assume this should work because rules for alias this (as I 
understand) are to basically try if there's a member name that 
resolves the call, else forward to alias this.


yeah, just built in properties/members don't pass the same 
existence checks so that's confusing your template constraint.


I believe the same happens if it's not a built in property. You 
can replace B!int with B!S and have S contains a function "f" 
(for instance), then whether or the not constraint on opDispatch 
is:


__traits(compiles, mixin("t." ~ name))
or
hasMember(T, name)

You still get:

b.p.writeln; // Error: no property 'p' for type 'B!(S)'




Re: Trying to forward unwrapped opDispatch names to alias this

2018-02-20 Thread aliak via Digitalmars-d-learn

On Tuesday, 20 February 2018 at 11:27:23 UTC, Alex wrote:

There is a related ticket,
https://issues.dlang.org/show_bug.cgi?id=6434
However, not exactly facing this question.


Should that ticket be marked as resolved? The issue is for alias 
this to be considered before opDispatch but there were no 
arguments after giving reasons for that being a bad idea. And 
opDispatch is considered before (and disables alias this) now it 
seems?




It seems, that currently opDispatch replaces alias this... (?)
Nevertheless, not only T is the wrapped type, but also A with 
the alias.
What to do, if both members have a property with the same name? 
And why?


Good question, should it be dealt with in the same way as this is 
dealt with?


struct S {
void f() {writeln("S");}
}
struct A {
S s; alias s this;
void f() {writeln("A");}
}
A().f; // prints "A"

However, the above behavior seems dangerous maybe and could lead 
to silent bugs. I'm thinking if A.f was not defined, then A().f 
would print "S". But then someone comes along and defines an A.f 
and the user of A now gets different functionality without even 
knowing about it. Hrm.. one is not sure how one feels :p


But how about if they do not have the same name? Currently 
AliasThis says: "If the member is a class or struct, undefined 
lookups will be forwarded to the AliasThis member."


So opDispatch, even though it's constrained, is not considered 
undefined if it doesn't pass. In those cases should it not be 
forwarded to the alias this? If not, then why does a constrained 
function not qualify as being undefined if the constraint doesn't 
pass?


Consider:

struct A {
void defined() {}
}

struct B {
void opDispatch(string name)() if (name == "defined") {}
}

void main() {
A().defined; // ok
B().defined; // ok
A().undefined;
B().undefined;
}

Errors are:
* Error: no property 'undefined' for type 'A', did you mean 
'defined'?

* Error: no property 'undefined' for type 'B'

If you then define a struct S that contains a function named 
"undefined" and add a "S s; alias s this;" inside A and B, you 
get:


* Error: no property 'undefined' for type 'B'

But not for A. Shouldn't the behavior here be consistent? Or why 
not?


Churr,
- Ali




Re: Trying to forward unwrapped opDispatch names to alias this

2018-02-20 Thread Adam D. Ruppe via Digitalmars-d-learn

On Monday, 19 February 2018 at 08:28:22 UTC, aliak wrote:
T is the wrapped type. So if T has a member (in the example 
it's the built in field "max") then forward that.


Oh, I see what you mean.

So the problem is that built in types don't have "members" per 
se, they have "magic". The built in properties don't count to 
`hasMember`. You could probably do `if(__traits(compiles, 
mixin("a." ~ member))` though.


I assume this should work because rules for alias this (as I 
understand) are to basically try if there's a member name that 
resolves the call, else forward to alias this.


yeah, just built in properties/members don't pass the same 
existence checks so that's confusing your template constraint.


  1   2   3   4   5   >