Re: Compile time data structure

2013-09-20 Thread Ali Çehreli

On 09/19/2013 12:53 PM, H. S. Teoh wrote:

 I hope you're
 thoroughly confused and utterly perplexed by now

No, because you explained it very well. :)

 readers should instead be directed to std.traits

Indeed, I will add some :) of this information to the Traits chapter 
which comes later in the book.


Ali



Re: Compile time data structure

2013-09-20 Thread Ali Çehreli

On 09/19/2013 04:32 AM, Dicebot wrote:

 Some obvious catches:

Thank you. I have made those changes except the following one.

 Variadic template arg chapter should probably mention variadic args of
 length 1 idiom used to have parameter accepting types, values and
 aliases at once.

Could you please expand on that.

Thank you,
Ali



Re: User defined attributes use

2013-09-20 Thread ilya-stromberg

On Monday, 16 September 2013 at 07:36:13 UTC, simendsjo wrote:
I don't have a full example without adding a lot of code, but 
this partial

example might give you the gist of it.


// This is the type that validates
struct matches(string mustMatch)
{
alias re = ctRegex!(mustMatch);

static string[] validate(T)(const ref T t)
{
static if(!isSomeString!T)
static assert(0, matches only works on strings, 
not ~T.stringof);

return match(t, re).empty ? [no match] : null;
}
}

// and this is the code that runs all validators for a variable
void validate(alias T)(ref Appender!(string[]) app)
{
static if(isTupleWrapper!T)
{
validate!(T.Head)(app);
validate!(T.Tail)(app);
}
else
{
foreach(memberAttr; getValidaterAttrs!T)
{
foreach(attr; memberAttr.Tail)
{
foreach(msg; attr.validate(T))
if(msg.length)
app.put(msg);
}
}
}
}

// .. And here is some of the plumbing

string[] validate(Vars...)()
{
auto app = appender!(string[])();
validate!Vars(app);
return app.data();
}


// The getMembersAndAttributesWhere are templates in my little 
library that isn't released. Uses quite some custom __traits 
stuff, but it's basically __traits(getAttributes

template getValidaterAttrs(alias T)
{
alias getValidaterAttrs = 
TypeTuple!(getMembersAndAttributesWhere!(T, 
isValidationAttr).Elements,
 
getMembersAndAttributesWhere!(TypeOf!T, 
isValidationAttr).Elements);

}

// Well.. Incomplete
template isValidationAttr(alias T)
{
enum isValidationAttr = hasMember!(TypeOf!T, validate);
}


Can I explicitly specify when I can use attribute? Something like
this:

@attribute(field)
struct matches(string mustMatch)
{
}

string wrongAttribute
{
}

class Foo
{
@matches([0-9]+)
string someNumber; //OK, it's a field
}

@matches([0-9]+) //Error, it's a class, not a field
class Bar
{
}

@wrongAttribute //Error, this attribute doesn't exist
class C
{
}


Re: User defined attributes use

2013-09-20 Thread Jacob Carlborg

On 2013-09-20 08:59, ilya-stromberg wrote:


Can I explicitly specify when I can use attribute? Something like
this:

@attribute(field)
struct matches(string mustMatch)
{
}

string wrongAttribute
{
}

class Foo
{
 @matches([0-9]+)
 string someNumber; //OK, it's a field
}

@matches([0-9]+) //Error, it's a class, not a field
class Bar
{
}

@wrongAttribute //Error, this attribute doesn't exist
class C
{
}


Unfortunately you can't. I tag all my structs which are supposed to be 
used as UDA's with a @attribute UDA.


struct attribute {}

@attribute struct matches(string mustMatch) {}

Then I have some wrappers around __traits(getAttributes) that will, by 
default, only return UDA's that them self have the @attribute UDA 
attached to them.


https://github.com/jacob-carlborg/orange/blob/master/orange/core/Attribute.d

--
/Jacob Carlborg


Re: References

2013-09-20 Thread andrea9940

Remove the ref in ref A opAdd(const ref A a) {


References

2013-09-20 Thread andrea9940

Running this code I would expect to get ref three times, but ...

---
import std.stdio;
struct A {
int[128] data;
ref A opAdd(const ref A a) {
A cp = this;
cp.data[] += a.data[];
return cp;
}
}

void fun(A a) { writeln(copy); }
void fun(const ref A a) { writeln(ref); }

void main() {
A a, b;
fun(a + b); //prints copy
fun(A());   //prints copy
fun(a); //prints copy
}
---

After some tests I concluded that is not possible to pass the 
result of a+b as a reference (which is what interests me most) 
and this creates an evident performance problem.

Is there any solution that I missed ?


Re: References

2013-09-20 Thread Namespace

On Friday, 20 September 2013 at 09:36:18 UTC, andrea9940 wrote:
Running this code I would expect to get ref three times, but 
...


---
import std.stdio;
struct A {
int[128] data;
ref A opAdd(const ref A a) {
A cp = this;
cp.data[] += a.data[];
return cp;
}
}

void fun(A a) { writeln(copy); }
void fun(const ref A a) { writeln(ref); }

void main() {
A a, b;
fun(a + b); //prints copy
fun(A());   //prints copy
fun(a); //prints copy
This prints 'ref' if you change func(A a) to func(const A a) the 
match of const ref isn't prefered over A a because const need an 
implicit conversion.

}
---

After some tests I concluded that is not possible to pass the 
result of a+b as a reference (which is what interests me most) 
and this creates an evident performance problem.

Is there any solution that I missed ?


a + b is an rvalue and will moved to func(A a). This is even 
faster than ref. ;)

A() is also moved.
If you have two functions, one with const A a and one with ref 
const A a, the latter accepts lvalues which are passed by ref and 
the first accepts rvalues which are moved. So no performance 
problem. ;)
If you're function is a template you can use 'auto ref' which 
automatically generate two versions of your function: one with 
and one without ref.


Re: References

2013-09-20 Thread andrea9940

On Friday, 20 September 2013 at 09:44:51 UTC, Namespace wrote:

This prints 'ref' if you change func(A a) to func(const A a) 
the match of const ref isn't prefered over A a because const 
need an implicit conversion.

Thanks for the tip.

a + b is an rvalue and will moved to func(A a). This is even 
faster than ref. ;)

A() is also moved.
Mmm... here is the assembly generated (with -release -O), it 
seems to me that the struct is always copied.


; fun(a + b)
LEA EAX,[EBP-604]
PUSH EAX
LEA EAX,[EBP-404]
PUSH EAX
LEA EAX,[EBP-804]
CALL 00402010 ;opAdd()
MOV EBX,EAX   ;pointer to the stack
MOV ECX,80
ADD EBX,1FC
004020C3: PUSH DWORD PTR DS:[EBX] ; copy !
SUB EBX,4 ; copy !
LOOP SHORT 004020C3   ; copy !
CALL 00402048 ; fun(const A a)

;fun(A())
PUSH 80
MOV EAX,OFFSET 00422930
PUSH EAX
CALL 00405DB0
MOV DWORD PTR SS:[EBP-4],EAX
MOV ECX,DWORD PTR SS:[EBP-4]
XOR EAX,EAX
MOV DWORD PTR DS:[ECX],EAX
MOV EAX,DWORD PTR SS:[EBP-4]
MOV DWORD PTR DS:[EAX+4],0
; a lot of movs later ...
MOV EAX,DWORD PTR SS:[EBP-4]
MOV DWORD PTR DS:[EAX+1FC],0
MOV ESI,DWORD PTR SS:[EBP-4]
LEA EDI,[EBP-204]
MOV ECX,80
REP MOVS DWORD PTR ES:[EDI],DWORD PTR DS:[ESI]
ADD ESP,8
; ^ a lot of istructions to set a struct to zero imo
LEA EBX,[EBP-8]
MOV ECX,80
0040271B: PUSH DWORD PTR DS:[EBX]; copy !
SUB EBX,4; copy !
LOOP SHORT 0040271B  ; copy !
CALL 00402048 ;fun(const A a)

; fun(a)
LEA EAX,[EBP-804]  ;load the reference
CALL 00402060  ; fun(const ref A a)


Re: References

2013-09-20 Thread Namespace

On Friday, 20 September 2013 at 10:29:24 UTC, andrea9940 wrote:

On Friday, 20 September 2013 at 09:44:51 UTC, Namespace wrote:

This prints 'ref' if you change func(A a) to func(const A a) 
the match of const ref isn't prefered over A a because const 
need an implicit conversion.

Thanks for the tip.

a + b is an rvalue and will moved to func(A a). This is even 
faster than ref. ;)

A() is also moved.
Mmm... here is the assembly generated (with -release -O), it 
seems to me that the struct is always copied.


; fun(a + b)
LEA EAX,[EBP-604]
PUSH EAX
LEA EAX,[EBP-404]
PUSH EAX
LEA EAX,[EBP-804]
CALL 00402010 ;opAdd()
MOV EBX,EAX   ;pointer to the stack
MOV ECX,80
ADD EBX,1FC
004020C3: PUSH DWORD PTR DS:[EBX] ; copy !
SUB EBX,4 ; copy !
LOOP SHORT 004020C3   ; copy !
CALL 00402048 ; fun(const A a)

;fun(A())
PUSH 80
MOV EAX,OFFSET 00422930
PUSH EAX
CALL 00405DB0
MOV DWORD PTR SS:[EBP-4],EAX
MOV ECX,DWORD PTR SS:[EBP-4]
XOR EAX,EAX
MOV DWORD PTR DS:[ECX],EAX
MOV EAX,DWORD PTR SS:[EBP-4]
MOV DWORD PTR DS:[EAX+4],0
; a lot of movs later ...
MOV EAX,DWORD PTR SS:[EBP-4]
MOV DWORD PTR DS:[EAX+1FC],0
MOV ESI,DWORD PTR SS:[EBP-4]
LEA EDI,[EBP-204]
MOV ECX,80
REP MOVS DWORD PTR ES:[EDI],DWORD PTR DS:[ESI]
ADD ESP,8
; ^ a lot of istructions to set a struct to zero imo
LEA EBX,[EBP-8]
MOV ECX,80
0040271B: PUSH DWORD PTR DS:[EBX]; copy !
SUB EBX,4; copy !
LOOP SHORT 0040271B  ; copy !
CALL 00402048 ;fun(const A a)

; fun(a)
LEA EAX,[EBP-804]  ;load the reference
CALL 00402060  ; fun(const ref A a)


If you have doubt about the assembly, please feeld free to open a 
bug report.


And for performance:

import std.stdio;

struct A {
public:
uint id;

this(uint id) {
this.id = id;

writeln(CTor A with , id);
}

this(this) {
writeln(Postblit A with , this.id);
}

~this() {
writeln(DTor A with , this.id);
}

A opBinary(string op : +)(ref const A a) {
return A(this.id + a.id);
}
}

void func(const A a) {
writeln(Value call with A::, a.id); 
}

void func(ref const A a) {
writeln(Ref call with A::, a.id);
}

void main()
{

A a = A(42);
A b = A(23);

func(a + b);
func(A(1337));
func(a);
}


Output:

CTor A with 42
CTor A with 23
CTor A with 65
Value call with A::65
DTor A with 65
CTor A with 1337
Value call with A::1337
DTor A with 1337
Ref call with A::42
DTor A with 23
DTor A with 42


No Postblit call.


Re: References

2013-09-20 Thread andrea9940

Output:

CTor A with 42
CTor A with 23
CTor A with 65
Value call with A::65
DTor A with 65
CTor A with 1337
Value call with A::1337
DTor A with 1337
Ref call with A::42
DTor A with 23
DTor A with 42


No Postblit call.


The beahvior is correct but at assembly level the compiler still 
creates a copy on the stack.


D code: http://pastebin.com/sTLhnNdV
Disassembly: http://pastebin.com/5emmwqJc

I'll post a bug report. Thanks for everything.


Re: Compile time data structure

2013-09-20 Thread Dicebot

On Friday, 20 September 2013 at 06:20:09 UTC, Ali Çehreli wrote:

On 09/19/2013 04:32 AM, Dicebot wrote:

 Some obvious catches:

Thank you. I have made those changes except the following one.

 Variadic template arg chapter should probably mention
variadic args of
 length 1 idiom used to have parameter accepting types,
values and
 aliases at once.

Could you please expand on that.

Thank you,
Ali


Quoting Phobos:

```
template fullyQualifiedName(T...)
if (T.length == 1)
{
static if (is(T[0]))
enum fullyQualifiedName = 
fullyQualifiedNameImplForTypes!(T[0], false, false, false, false);

else
enum fullyQualifiedName = 
fullyQualifiedNameImplForSymbols!(T[0]);

}
```

It is a relatively common idiom because there is no other way to 
express a single template parameter that accepts anything.


Re: User defined attributes use

2013-09-20 Thread simendsjo
On Friday, 20 September 2013 at 07:57:43 UTC, Jacob Carlborg 
wrote:

On 2013-09-20 08:59, ilya-stromberg wrote:

Can I explicitly specify when I can use attribute? Something 
like

this:

@attribute(field)
struct matches(string mustMatch)
{
}

string wrongAttribute
{
}

class Foo
{
@matches([0-9]+)
string someNumber; //OK, it's a field
}

@matches([0-9]+) //Error, it's a class, not a field
class Bar
{
}

@wrongAttribute //Error, this attribute doesn't exist
class C
{
}


Unfortunately you can't. I tag all my structs which are 
supposed to be used as UDA's with a @attribute UDA.


struct attribute {}

@attribute struct matches(string mustMatch) {}

Then I have some wrappers around __traits(getAttributes) that 
will, by default, only return UDA's that them self have the 
@attribute UDA attached to them.


https://github.com/jacob-carlborg/orange/blob/master/orange/core/Attribute.d


You could of course fix this in a library too.

enum AttributeUsage {
  struct_ = 1  0,
  class_ = 1  1,
  //etc
}

struct attribute { AttributeUsage usage; }

Then the library could give a compile-time error if you tries to 
use it where it's not meant to be.


Re: non virtual interfaces

2013-09-20 Thread Alexandr Druzhinin

20.09.2013 12:45, Ali Çehreli пишет:

On 09/19/2013 10:31 PM, Alexandr Druzhinin wrote:

  if I use protected instead of private in interface like:

private member functions are non-virtual.
But I just use code example from TDPL russian edition. And TDPL says 
clearly that (un)transmogrify() are private and CardboardBox _maynot_ 
make (un)transmogrify() non-private - this is highlighted as compiler 
support of NVI idiom. Is it wrong example, I guess?


  interface Transmogrifier
  {
   final void thereAndBack()
   {
   transmogrify();
   untransmogrify();
   }
 
   protected:
   void transmogrify();
   void untransmogrify();
  }

If they were non-virtual (i.e. private), the calls to transmogrify() and
untransmogrify() from thereAndBack() would be bound to
Transmogrifier.transmogrify and Transmogrifier.untransmogrify at compile
time. That happens and the linker cannot find their definitions.

I see. Thanks, I understand it now better


  class CardboardBox: Transmogrifier
  {
   override protected void transmogrify() { }
   override void untransmogrify() {}
  }

  it compiles, but why does compiler permit making untransmogrify() be
  public?

It is up to CardboardBox to decide whether untransmogrify() is public or
not. Note that untransmogrify() is still protected when objects are used
through the Transmogrifier interface. However, when an object is known
to be a CardboardBox so that it is being used through the CardboardBox
interface, it is not bound to be a Transmogrifier at that point. Yes,
CardboardBox inherits from Transmogrifier but it is CardboardBox's
interface that is being used at that point so it decides.
Thanks again. So there is no compiler support for NVI idiom? Because if 
CardboardBox may define its own (un)transmogrify() - TDPL says it 
possible only if (un)transmogrify() have other signatures.


  How can I prohibit this? May be it just unrealized yet?

You cannot prohibit from Transmogrifier.

Ali


Unfortunately I tried to use NVI for it namely.


Re: non virtual interfaces

2013-09-20 Thread Jonathan M Davis
On Friday, September 20, 2013 22:40:48 Alexandr Druzhinin wrote:
 20.09.2013 12:45, Ali Çehreli пишет:
  On 09/19/2013 10:31 PM, Alexandr Druzhinin wrote:
if I use protected instead of private in interface like:
  private member functions are non-virtual.
 
 But I just use code example from TDPL russian edition. And TDPL says
 clearly that (un)transmogrify() are private and CardboardBox _maynot_
 make (un)transmogrify() non-private - this is highlighted as compiler
 support of NVI idiom. Is it wrong example, I guess?

TDPL is mostly correct but not completely correct. AFAIK, it has never been 
implemented that you can override private functions in interfaces like TDPL 
describes. With classes, package and private are _never_ virtual, so private 
will have be treated differently interfaces in order to do what TDPL describes. 
That may or may not be implemented in the future.

You can use NVI with classes just fine just so long as you use protected rather 
than private, but making it private there won't work either, because private 
is never virtual (and it wouldn't really help you any if it were, because 
while the base class private function might not be callable, the derived class 
one would still be callable by the derived class, so trying to prevent the 
virtual function in NVI from ever being called outside of the base class is 
broken in the first place - including in C++ where it was originally devised). 
What NVI helps with is making it so that the public function being called as 
part of the API is non-virtual, allowing you to do stuff before and after the 
hidden virtual function being called, but the derived classes can still call 
their implementation of the hidden, virtual function.

- Jonathan M Davis


Re: non virtual interfaces

2013-09-20 Thread Alexandr Druzhinin

20.09.2013 23:09, Jonathan M Davis пишет:

You can use NVI with classes just fine just so long as you use protected rather
than private, but making it private there won't work either, because private
is never virtual (and it wouldn't really help you any if it were, because
while the base class private function might not be callable, the derived class
one would still be callable by the derived class, so trying to prevent the
virtual function in NVI from ever being called outside of the base class is
broken in the first place - including in C++ where it was originally devised).
What NVI helps with is making it so that the public function being called as
part of the API is non-virtual, allowing you to do stuff before and after the
hidden virtual function being called, but the derived classes can still call
their implementation of the hidden, virtual function.

- Jonathan M Davis


I see. Thanks for clarifying.