Re: Operator overloading through UFCS doesn't work

2012-10-16 Thread Tommi

On Monday, 15 October 2012 at 09:33:23 UTC, Maxim Fomin wrote:

---foo.d---
struct A
{
   int i;
   alias i this;
}
---bar.d---
int opUnary(string T)(A a) { ... }
...
{
  ++a;
}
---
I. i is incremented, opUnary is not called. However opUnary 
matches better to the actual type and if it were a method, it 
would be called - another special issue in the language which 
breaks usual logic. And if you declared opUnary in bar.d when 
alias this was absent in foo.d and later added - hijacking also 
occurs but now it happens from another side. Bad.


Let's talk about the semantics of the word hijacking as it 
relates to this discussion. Here's my take on it:


Let type T have some inherent functionality F. That is, 
functionality F cannot be removed from T without making changes 
to the module file where type T is defined. Then, if some other 
functionality F' overrides (replaces and modifies) F, it is said 
that F' hijacks F.


If I apply this definition to your example, we see that the free 
function opUnary in bar.d is *not* part of struct A's inherent 
functionality. Therefore, by adding later that alias this in A's 
definition, we are *not* hijacking anything.


Furthermore, if that free function opUnary was defined in foo.d 
instead, it would be an inherent part of A's functionality. Then, 
by adding later that alias this in A's definition, we would be 
*changing* A's functionality. But that's not hijacking, because 
we're making the change in the module file where A is defined. 
That's not hijacking, that's just changing the inherent 
functionality of your own user-defined type.


Re: Operator overloading through UFCS doesn't work

2012-10-14 Thread Tommi

On Sunday, 14 October 2012 at 06:22:03 UTC, Maxim Fomin wrote:

On Saturday, 13 October 2012 at 17:01:27 UTC, Tommi wrote:

Another way to describe my reasoning...

According to TDPL, if var is a variable of a user-defined 
type, then:

++var
gets rewritten as:
var.opUnary!++()


Not always. If user-defined type has an alias this to integer 
member, than something different would happen.


Yeah, I wasn't specific enough with that example.

It would be also interesting to see, how operation ++T would 
differ because somebody imported module with opUnary method. 
Because opUnary suits better than alias this, dmd will issue 
call to that function, it it see its declaration.


Actually, it seems that alias this has precedence over UFCS. So, 
a free function opUnary wouldn't ever suit better than an actual 
method opUnary of the thing referred to by that alias this.


Re: Operator overloading through UFCS doesn't work

2012-10-14 Thread Tommi

On Sunday, 14 October 2012 at 07:14:25 UTC, Maxim Fomin wrote:
If this request is approved and compiler has opUnary definition 
outside type (which suits better then alias

this) such function would hijack alias this.


Free functions cannot and must not ever hijack, i.e. modify 
existing functionality of a type. Free functions should only be 
able to add new functionality to a type. This is what currently 
happens with alias this vs free function which is accessed 
through UFCS:


struct B
{
void fun()
{
writeln(B.fun());
}
}

struct A
{
B b;
alias b this;
}

void fun(A a)
{
writeln(.fun(A));
}

void main()
{
A a;
a.fun(); // prints B.fun() as it should
}

It shouldn't be any different if fun was some operator function, 
like opUnary; the free function mustn't hijack type A's existing 
functionality (which is currently being provided to A by that 
alias this thingy).


Operator overloading through UFCS doesn't work

2012-10-13 Thread Tommi
Quote from TDPL: D’s approach to operator overloading is 
simple: whenever at least one participant in an operator 
expression is of user-defined type, the compiler rewrites the 
expression into a regular method call with a specific name. Then 
the regular language rules apply.


According to the above, I think the following code should work:

struct MyStruct
{
int _value;
}

ref MyStruct opUnary(string op : ++)(ref MyStruct ms)
{
++ms._value;
return ms;
}

MyStruct opBinary(string op : +)(MyStruct ms, int value)
{
return MyStruct(ms._value + value);
}

void main()
{
MyStruct ms;

ms.opUnary!++(); // #1: OK
MyStruct ms2 = ms.opBinary!+(1); // #2: OK

++ms;  // #3
MyStruct ms3 = ms + 1; // #4
}

#3: Error: 'ms += 1' is not a scalar, it is a MyStruct

#4: Error: incompatible types for ((ms) + (1)):
'MyStruct' and 'int'


I'd expect the lines tagged #3 and #4 to be rewritten by the 
compiler like so:

ms.opUnary!++();
MyStruct ms3 = ms.opBinary!+(1);

So, the inability to do operator overloading though UFCS must be 
a compiler bug, right?


Re: Operator overloading through UFCS doesn't work

2012-10-13 Thread Tommi

On Saturday, 13 October 2012 at 09:06:28 UTC, Jakob Ovrum wrote:
Do note that this says *method* call. Your example doesn't use 
methods. Hence, the current state of operator overloading is 
consistent with TDPL.


I don't agree with the last sentence. According to TDPL:

1) whenever at least one participant in an operator expression
is of user-defined type, the compiler rewrites the expression
into a regular method call with a specific name
---
++var;
gets rewritten to:
var.opUnary!++();

2) if a.fun(b, c, d) is seen but fun is not a member of a’s
type, D rewrites that as fun(a, b, c, d) and tries that as well

So, because opUnary is not a member of var, compiler should 
rewrite that as:

.opUnary!++(var);


Re: Operator overloading through UFCS doesn't work

2012-10-13 Thread Tommi
On Saturday, 13 October 2012 at 09:50:05 UTC, Jonathan M Davis 
wrote:

It is most definitely _by design_ that you cannot
overload operators except as member functions.


I don't understand this design choice then. I don't see any 
problem in allowing UFCS operators. Because of the way UFCS 
works, it's guaranteed that there can't be any operator hijacking.


Re: Operator overloading through UFCS doesn't work

2012-10-13 Thread Tommi

On Saturday, 13 October 2012 at 11:50:40 UTC, Maxim Fomin wrote:
I think implementing UFCS operator overloading is problematic. 
Firstly, you want to put this language addition too far.


I don't see this as taking UFCS functionality further. Rather, 
I think it's simply more logical that with UFCS you could provide 
extra operator methods just like you can provide extra regular 
methods. I assumed that UFCS operator overloading would work for 
sure, and it seems arbitrary to me that it doesn't.



Secondly, compiler needs to know whether operator was 
overloaded or not. If it knows, it generates code to call 
opSomething, if nor - it just doesn't generate anything. Now, 
imagine what would happen if you write in some module free 
function, supposed to hijack operator overloading method of 
class or struct in another module. If you compile them 
together, operator would be overloaded, if separately - nothing 
would happen. This means that operator overloading would depend 
on with what you compile your module - sometimes nothing would 
be overloaded, sometimes it would be with one function, 
sometimes with another.


You use the word hijack, but free functions can't hijack 
anything. They can only provide new functionality. The situation 
you describe is exactly parallel to using UFCS (with regular 
functions) like this:


//File: mystruct.d
module mystruct;

struct MyStruct
{
int _value;
}

//File: incr1.d
module incr1;

import mystruct;

void incr(ref MyStruct ms)
{
ms._value += 1;
}

//File: incr2.d
module incr2;

import mystruct;

void incr(ref MyStruct ms)
{
ms._value += 2;
}

//File: main.d
module main;

import std.stdio;
import mystruct;

static if (true) // change to false to print 2
import incr1;
else
import incr2;

void main()
{
MyStruct ms;
ms.incr();
writeln(ms._value); // prints 1
}


Thirdly, I see no reason in allowing it - for what purpose does 
you proposal service for?


The main reason to me is that it would make more sense. It'd seem 
more logical that way. I can't think of any use cases.


Re: Operator overloading through UFCS doesn't work

2012-10-13 Thread Tommi

On Saturday, 13 October 2012 at 16:02:25 UTC, Maxim Fomin wrote:

From my point of view operator overloading methods are
special functions and not treating them as candidates for
UFCS does make more sense.


I can think of only one thing that makes custom operator methods 
special or different from regular methods. It's the fact that 
you don't *have* to call them through the normal method 
invocation syntax: var.opSomething(...), but rather, the language 
provides this nice layer of syntactic sugar through which you 
*can* call those methods, if you so choose to.


What you're saying is, that calling those operator methods 
through this layer of syntactic sugar, e.g. var + 3, is somehow 
fundamentally different from directly calling the method, to 
which this layer of syntactic sugar would forward the expression 
to call anyway, i.e. var.opBinary!+(3)


Re: Operator overloading through UFCS doesn't work

2012-10-13 Thread Tommi

Another way to describe my reasoning...

According to TDPL, if var is a variable of a user-defined type, 
then:

++var
gets rewritten as:
var.opUnary!++()

Thus, it would be very logical to assume that it doesn't matter 
whether you write:

++var
...or, write the following instead:
var.opUnary!++()
...because the second form is what the first form gets written to 
anyway.


But, that very logical assumption turns out to be wrong. 
Because in D, as it stands currently, it *does* make a difference 
whether you write it using the first form or the second:


struct S
{
int _value;
}

ref S opUnary(string op : ++)(ref S s)
{
++s._value;
return s;
}

Now, writing the following compiles and works:
S var;
var.opUnary!++();

...while the following doesn't compile:
S var;
++var;

This behavior of the language is not logical. And I don't think 
that logic is a matter of preference or taste.


Function pointer variable not recognized as function by is-operator

2012-10-07 Thread Tommi
The following compiles, which I'm pretty sure must be a bug, 
right? Just checking to be sure I won't be polluting the bug 
tracker.


void main()
{
auto f = (int i) {};
static assert (!is(f == function)); // should fail
static assert (!is(f == delegate));
}



Re: How to iterate all k-subsets of a range in a specific order?

2012-10-05 Thread Tommi

Although, the only case, where this would be
a problem is with a range of type T, where:

1) It's impossible to provide random access to T
2) T can't return a reference from its 'front' property
3) T is a finite range (not infinite)
4) 'front' property may return the same value at different indexes

Something like:

struct R
{
int _value = 0;
int _round = 1;

@property bool empty() const
{
return _value == 100  _round == 2;
}

@property int front() const
{
return _value;
}

void popFront()
{
if (_value == 99)
{
if (_round == 1)
{
_value = 0;
_round = 2;
}
else
{
_value = 100;
}
}
else
{
++_value;
}
}
}

Albeit, in this simple example it would be possible to provide 
random access to R, because the sequential definition of it could 
be easily replaced with an algebraic one. But for a more complex 
sequential definition, it might not be possible. So, the 
situation, where this (potential) defect of the range concept 
would be a problem, seems very rare, but it's nevertheless 
possible.




Re: How to iterate all k-subsets of a range in a specific order?

2012-10-05 Thread Tommi

On Friday, 5 October 2012 at 09:37:51 UTC, Ali Çehreli wrote:


This brings up a question: Should all range types implement 
opEquals() for range equality as opposed to identity 
equality of the underlying range (i.e. Take.source in this 
case).


But even if the range concept was altered so that all ranges have 
to implement opEquals(), it wouldn't be a very satisfying 
solution. That's because opEquals() could be a very slow function 
for some ranges, e.g. forward ranges, where you have to check 
each element's equality one by one. Using opEquals() like that 
could make traversing those subset iterations very slow.




What does 'd' in dchar stand for?

2012-10-05 Thread Tommi

What does 'd' in dchar and dstring stand for?


Re: Functional vs simple code

2012-10-02 Thread Tommi

On Wednesday, 3 October 2012 at 01:21:38 UTC, ixid wrote:

If it were (range, seed) then there would be no problem:

[1,1,1].reduce!a + b + 2(0).writeln; // == 9


My thoughts exactly.


Re: Very strange problem with comparing floating point numbers

2012-09-30 Thread Tommi
On Sunday, 30 September 2012 at 01:48:04 UTC, Andrej Mitrovic 
wrote:


Dissasembly:
__Dmain:; Function begin, communal
enter   12, 0   ;  
_ C8, 000C, 00
call_D4test8getFloatFNdZf   ; 0004 
_ E8,

(rel)
...


Can I tell DMD to produce the assembly, or what did you do to get 
that?


Re: Struct assignment, possible DMD bug?

2012-09-29 Thread Tommi

On Saturday, 29 September 2012 at 18:16:24 UTC, Timon Gehr wrote:

This seems to be a DMD bug.


And a pretty serious looking one at that. That bug could make 
nukes fly to wrong coordinates, and that just ruins everybody's 
day.


Re: Is it possible to force CTFE?

2012-09-28 Thread Tommi
One use case I can think of for specializing functions based on 
whether or not its arguments are compile-time evaluable:


// Big container that can't be accessed in constant time:
immutable cachedResults = init();

double getResult(args)
if (areCompileTimeConstants!(args) == false)
{
return cachedResults.at(args);
}

double getResult(args)
if (areCompileTimeConstants!(args) == true)
{
// Computing the result takes long time
...
return computedResult;
}

Point being that A) cachedResults takes so much memory we don't 
want to evaluate it at compile-time and bloat the executable, and 
B) accessing cachedResults takes some non-trivial time, so we 
don't want to do that at runtime if it can be done at 
compile-time. Don't know how common this kind of thing would be 
though.



But, that made me think...
In a perfect world, I think, the compiler would always evaluate 
all possible functions at compile-time, given that doing so would 
produce a smaller (or equal size) executable than what 
not-evaluating-at-compile-time would produce. For example 
(assuming the following initialization functions are compile-time 
evaluable):


// The following wouldn't be evaluated at compile time,
// because that function call (probably) wouldn't take
// as much space in the executable as million ints:

int[1_000_000] bigArray = initBigArray();

// The following would be always evaluated at compile time,
// because a single int value would take less space in the
// executable than the function call:

int myValue = initMyValue();

Although, to speed up test compilations, we'd need a compiler 
flag to disable this aggressive CTFE behaviour.


Re: Is it possible to force CTFE?

2012-09-28 Thread Tommi

On Friday, 28 September 2012 at 17:52:55 UTC, Tommi wrote:
In a perfect world, I think, the compiler would always evaluate 
all possible functions at compile-time, given that doing so 
would produce a smaller (or equal size) executable than what 
not-evaluating-at-compile-time would produce.



Or, a simpler rule (for both the compiler and the coder):
Have a compiler flag where you set a value (in bytes), and if a 
function returns a type that's size is not larger than the set 
value, the compiler would execute all calls to that function at 
compile-time (if possible).


Re: Is it possible to force CTFE?

2012-09-27 Thread Tommi

On Sunday, 10 June 2012 at 10:16:23 UTC, jerro wrote:


No, but you could wrap it in a template to force it to always
execute at compile time.


So, I just realized, I could have just this one convenience 
template that I can use whenever I want to force an expression to 
be evaluated at compile-time. Like so:


template ct(alias expr)
{
 enum ct = expr;
}

int fun(int a, int b)
{
 return a + b;
}

//... and use it like:

ct!(fun(1, 2))

That's not *too* inconvenient. Although, best would be a function 
attribute that would force the compiler to apply ctfe 
aggressively whenever it can with calls to that function.


Re: Reading bytes and converting to int

2012-08-26 Thread Tommi
On Saturday, 25 August 2012 at 20:58:47 UTC, Jonathan M Davis 
wrote:

auto buf = file.rawRead(new ubyte[](4));


Could we somehow skip making the temporary buffer, and read from 
the file directly into an existing variable. Can we make a slice 
of one element that points to an existing value.


import std.stdio;

struct BigValue // has no indirection
{
int  m_value1;
int  m_value2;
long m_value3;
// ...
}

BigValue g_bigValue;

void fun()
{
auto file = File(filename);

// How to create a slice of size 1 which references 
g_bigValue?

BigValue[] refToBigValue /* = ? */ ;

buffer = file.rawRead(refToBigValue);
}


Re: Reading bytes and converting to int

2012-08-26 Thread Tommi

On Sunday, 26 August 2012 at 15:18:27 UTC, Timon Gehr wrote:


auto refToBigValue = (g_bigValue)[0..1];



Thanks. Oughta read the f***ing manual instead of glancing 
through it:

http://dlang.org/arrays.html


Getting the underlying type of enum?

2012-07-17 Thread Tommi
How would you go about retrieving the exact underlying type of 
enum?


Re: Is this actually supposed to be legal?

2012-07-17 Thread Tommi
There's a thorough explanation of how incomplete types work in 
C++:

http://www.drdobbs.com/the-standard-librarian-containers-of-inc/184403814

And there's some more C++ related stuff:
http://www.boost.org/doc/libs/1_50_0/doc/html/container/containers_of_incomplete_types.html

I wouldn't know about D though.


Re: Immutable array initialization in shared static this

2012-07-16 Thread Tommi
Hmm.. actually, it seems there have been plenty of reports of 
this issue already. Didn't see it the first time:


http://d.puremagic.com/issues/show_bug.cgi?id=6174


How to make a unique copy in a generic manner?

2012-07-16 Thread Tommi
How do you make a (deep) copy of a variable of any type? For 
example the following attempt at a generic next function doesn't 
work, because it modifies its argument if the argument is a 
reference type.


T next(T)(in T value)
if (is(typeof(++[T.init][0]) == T))
{
auto copy = cast(T) value;
++copy;
return copy;
}

// For example, the following code outputs:
// 0
// 0
// 0
// 1

enum MyEnum
{
first,
second
}

struct MyStruct
{
int m_value;

ref MyStruct opUnary(string op)()
if (op == ++)
{
++m_value;
return this;
}
}

class MyClass
{
int m_value;

this(int value)
{
m_value = value;
}

ref MyClass opUnary(string op)()
if (op == ++)
{
++m_value;
return this;
}
}

void main(string[] args)
{
auto intZero = 0;
next(intZero);

auto enumZero = MyEnum.first;
next(enumZero);

auto structZero = MyStruct(0);
next(structZero);

auto classZero = new MyClass(0);
next(classZero);

writeln(intZero);
writeln(cast(int) enumZero);
writeln(structZero.m_value);
writeln(classZero.m_value);

stdin.readln();
}


Re: Immutable array initialization in shared static this

2012-07-14 Thread Tommi

On Friday, 13 July 2012 at 18:09:59 UTC, Era Scarecrow wrote:
 I would think the best solution is to create a mutable local 
version, and then assign the immutable global one when you are 
done.


Thanks for the workaround. But I'm actually more interested in 
whether or not this is a compiler bug or not, so that I could 
file a bug report. The following code makes me more certain that 
this in fact is a bug. Because in some sense there shouldn't be 
much difference between int and a fixed size int array of size 1:


module main;

import std.stdio;

immutable(int)value;
immutable(int[1]) staticArray;

shared static this()
{
value = 123;  // OK
staticArray[0] = 123; // Error: staticArray[0] isn't mutable
}

int main(string args[])
{
writeln(value);
readln();
return 0;
}




Immutable array initialization in shared static this

2012-07-13 Thread Tommi
The following code doesn't compile. It seems like a compiler bug 
to me, but I can't find a bug report about it. Is it a bug?


private immutable(int[]) constants;

shared static this()
{
constants.length = 10;
constants[0] = 123; // Error: constants[0] isn't mutable
}


Constraining template's function parameter signature

2012-06-14 Thread Tommi
I'm trying to constrain a struct template based on a parameter 
that's supposed be a function with a certain signature. Difficult 
to explain, easier just to show the problem:


module pseudorange;

struct PseudoInputRange(T, alias advance)
//The next line doesn't compile
//if (is(typeof(advance(T.init)) == void))
{
private:
T m_front;
T m_end;

public:
this(T begin, T end) pure nothrow
{
m_front = begin;
m_end = end;
}

@property immutable(T) front() const pure nothrow
{
return m_front;
}

void popFront() pure nothrow
{
advance(m_front);
}

@property bool empty() const pure nothrow
{
return m_front == m_end;
}
}

//...

module main;

import std.stdio;
import std.range;
import pseudorange;

int main(string[] argv)
{
alias PseudoInputRange!(int, (ref int x) {++x;}) MyRange;
static assert(isInputRange!MyRange);

foreach (x; MyRange(1, 11))
{
writeln(x);
}
stdin.readln();
return 0;
}


Is it possible to force CTFE?

2012-06-10 Thread Tommi

Three related questions:

1) Is there a way to force a function to be always executed at 
compile time (when it's possible to do so) no matter what context 
it's called in?


2) Is it possible to specialize a function based on whether or 
not the parameter that was passed in is a compile time constant?


3) Does any D compiler currently optimize out a conditional 
branch which _can_ be evaluated at compile time (but which isn't 
forced into CTFE)? Like:


int getValue(bool b)
{
return b ? 123 : 456;
}

//...
   auto value = getValue(true);


Re: Is it possible to force CTFE?

2012-06-10 Thread Tommi

On Sunday, 10 June 2012 at 10:23:09 UTC, Timon Gehr wrote:
No there is not. You could use a template that calls a private 
function at compile time instead. What is your use case?


I was just thinking about a situation where a property 
accessor/mutator methods are not as simple as read/assign value, 
such as in this silly example:


struct Flipping123
{
private int m_number = 123;

@property bool isPositive()
{
return m_number = 0;
}

@property void isPositive(bool b)
{
m_number = b ? 123 : -123;
}
}

//...
Flipping123 fl;
fl.isPositive = false; // I'd rather not have cond. branching 
in release mode