Re: Operator overloading through UFCS doesn't work
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
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).
Re: Operator overloading through UFCS doesn't work
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
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.
Re: Operator overloading through UFCS doesn't work
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
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
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
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);
Operator overloading through UFCS doesn't work
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?
Function pointer variable not recognized as function by is-operator
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)); }
What does 'd' in dchar stand for?
What does 'd' in dchar and dstring stand for?
Re: How to iterate all k-subsets of a range in a specific order?
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.
Re: How to iterate all k-subsets of a range in a specific order?
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: Functional vs simple code
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
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?
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?
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?
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() if (areCompileTimeConstants!() == false) { return cachedResults.at(); } double getResult() if (areCompileTimeConstants!() == 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?
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
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
Re: Reading bytes and converting to int
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: Is this actually supposed to be legal?
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.
Getting the underlying type of enum?
How would you go about retrieving the exact underlying type of enum?
How to make a unique copy in a generic manner?
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
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
Re: Immutable array initialization in shared static this
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
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 }
Using consistently auto as function return type
Do you consider it to be good or bad style of programming to use consistently auto as function return type? One of the pros is that it saves some redundant typing when the function returns some complex templated type: auto getValue() { return MyType!(int, "asdf", 64).init; } But one of the cons is that you don't see what the function returns just by looking at the signature. Are there some more severe issues that I'm missing?
Constraining template's function parameter signature
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; }
Re: Is it possible to force CTFE?
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
Is it possible to force CTFE?
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);