Re: Sorting a zipped range
On 02/27/2014 10:09 PM, Ben Jones wrote: My question is: which features of the D range abstraction allow zip to work the way we expect? Assignable elements of a range do not need to be addressable. What C++isms were left behind to make this work? In C++, iterators should implement operator-> which must return a pointer to data, and unary operator*, which should return a reference if it is to be assignable. This makes the iterator abstraction less flexible. I.e. it is a consequence of - desire to use pointer-like syntax for iterators - weak support for hooking into the corresponding syntactic constructs Phobos eg. allows retrieval of and assignment to a range's front element to be implemented in distinct methods that can execute arbitrary code. Zip uses such facilities to distribute assignments to its range elements back to each source range.
Re: DMD Source Guidance: Unused Return Values of Strictly Pure Function Calls
On 02/28/2014 12:38 AM, "Nordlöw" wrote: Does anybody know where in the DMD source I can figure out if the return value of a function call is used or not? I'm not familiar with the DMD source code, but a good way to proceed is usually to grep for existing error messages that are somehow related. In this case, DMD already complains about some cases of unused values: $ grep "no effect" *.c declaration.c: error("storage class 'auto' has no effect if type is not inferred, did you mean 'scope'?"); expression.c:e = new CastExp(loc, e, Type::tvoid); // avoid "has no effect" error mtype.c:// substitution has no effect on function pointer type. sideeffect.c: * Don't complain about an expression with no effect if it was cast to void sideeffect.c:/* Don't complain about calling functions with no effect, sideeffect.c:error("%s has no effect", toChars()); sideeffect.c:error("%s has no effect in expression (%s)", This leads directly to sideeffect.c: Expression::discardValue(), which seems to be the place where you want to insert your detection code.
Re: Function to print a diamond shape
On 03/20/2014 10:25 PM, Ali Çehreli wrote: This is a somewhat common little exercise: Write a function that takes the size of a diamond and produces a diamond of that size. When printed, here is the output for size 11: * *** * *** * *** * *** * *** * What interesting, boring, efficient, slow, etc. ways are there? Ali import std.stdio, std.range, std.algorithm, std.math; enum s=11; writef("%(%s\n%)", (i=>i.map!(a=>i.map!(b=>"* "[a+b>s/2]))) (iota(-s/2,s/2+1).map!abs));
Re: Choice ranges?
On 03/28/2014 08:00 PM, H. S. Teoh wrote: Today I ran into an interesting situation where I have a function f that needs to return ranges of different types (but identical element types): auto f(A...)(A args) { ... if (someCondition) return cartesianProduct(x, y) .joiner; else return cartesianProduct(x, y) .joiner .filter!someFilter; } This obviously can't compile, because the return types are not the same. (Note that someCondition is only known at runtime.) But abstractly speaking, it *should* work, because the element type of the returned range is identical. So how would I implement something like this? T The following is as close as I got. I think the definite initialization checks DMD implements are horribly broken for union fields. import std.range, std.algorithm, std.typetuple, std.traits; template CommonElementType(T...)if(allSatisfy!(isInputRange,T)){ alias CommonElementType = CommonType!(staticMap!(ElementType,T)); } private template Neg(alias a){ enum Neg(T...)=!a!T; } struct SumRange(T...)if(allSatisfy!(isInputRange,T)&&!is(void==CommonElementType!T)&&allSatisfy!(Neg!hasElaborateDestructor,T)&&allSatisfy!(Neg!hasElaborateCopyConstructor,T)){ size_t tag; private union{ T rs=void; } // private this(); @property front()@trusted{ switch(tag){ foreach(i,_;T) case i: return rs[i].front; default: assert(0); } } @property bool empty()@trusted{ switch(tag){ foreach(i,_;T) case i: return rs[i].empty; default: assert(0); } } void popFront()@trusted{ switch(tag){ foreach(i,_;T) case i: return rs[i].popFront(); default: assert(0); } } } private T buildSum(T, size_t tag,S)(S arg)@trusted{ T r; r.tag=tag; r.rs[tag]=arg; return r; } auto inl(T,S)(S arg)if(!hasElaborateDestructor!S&&!hasElaborateDestructor!T&&!hasElaborateCopyConstructor!S&&!hasElaborateCopyConstructor!T){ return buildSum!(SumRange!(S,T),0)(arg); } auto inr(S,T)(T arg)if(!hasElaborateDestructor!S&&!hasElaborateDestructor!T&&!hasElaborateCopyConstructor!S&&!hasElaborateCopyConstructor!T){ return buildSum!(SumRange!(S,T),1)(arg); } auto f(R,S)(bool condition,R x,S y){ auto r1(){ return cartesianProduct(x, y).map!(a=>[a.expand]) .joiner; } auto r2(){ return cartesianProduct(x, y).map!(a=>[a.expand]) .joiner .filter!(a=>a>2); } if(condition) return r1().inl!(typeof(r2())); else return r2().inr!(typeof(r1())); } void main(){ import std.stdio; writeln(f(true, [1,2,3], [4,5,6])); writeln(f(false, [1,2,3], [4,5,6])); }
Re: Choice ranges?
On 03/29/2014 01:37 AM, Artur Skawina wrote: You can wrap the range in a common one. When the above approach isn't enough, there's always the next level: (Note that your code does not actually compile.)
Re: Choice ranges?
On 03/29/2014 06:19 PM, Artur Skawina wrote: Of course it compiles -- with the compiler version I happen to use... The compiler situation is one of the main reasons I gave up on D about a year ago. Every release introduces a new dialect. This may not be such a big problem for trivial toy programs, but for anything else it means that the only practical approach is locking the toolchain down and never looking forward. Sometimes this means that the examples I post won't work -- I don't have any newer D compiler to check with, sorry. I'm stuck with 2.060 myself, but there's always http://dpaste.dzfl.pl/.
Re: They are not the same
On 04/05/2014 11:53 AM, bearophile wrote: John Colvin: I think there's an argument that this should work, on the grounds that the context pointer is just another argument and therefore the lambda can be weakly pure. Was this discussed in the forum? I've been bringing this up time and time again, but it is usually ignored. Do you think you can ask for an enhancement in Bugzilla? ... It's a plain bug. In fact, you have commented on it: https://d.puremagic.com/issues/show_bug.cgi?id=9148
Re: They are not the same
On 04/05/2014 10:33 PM, Artur Skawina wrote: On 04/05/14 21:51, Timon Gehr wrote: On 04/05/2014 11:53 AM, bearophile wrote: John Colvin: I think there's an argument that this should work, on the grounds that the context pointer is just another argument and therefore the lambda can be weakly pure. Was this discussed in the forum? I've been bringing this up time and time again, but it is usually ignored. Do you think you can ask for an enhancement in Bugzilla? ... It's a plain bug. In fact, you have commented on it: https://d.puremagic.com/issues/show_bug.cgi?id=9148 You're asking for bypassing immutability there (The first 'bar'. Good point, presumably this was a copy-and-paste error. That second 'bar' does not make sense w/o properly typed delegates; The issue asks for delegates to be typed properly, unless I misunderstand what 'properly' means here. the second 'foo' should indeed work). artur
Re: Empty array and AA literals
On 04/06/2014 05:28 AM, dnspies wrote: int[][] nested; nested ~= null; ~ is overloaded, so how does it know what type I intend null to be? How can I specify it? (int[]).init
Re: They are not the same
On 04/09/2014 07:27 PM, Kagamin wrote: On Saturday, 5 April 2014 at 21:33:30 UTC, Timon Gehr wrote: The issue asks for delegates to be typed properly, unless I misunderstand what 'properly' means here. Isn't the issue in pure nested functions treated as strongly pure? What does it have to do with delegates? The issue is that pure nested functions and delegate literals are not allowed mutable access to data reachable using context pointers. However, this may also be exactly what is wanted in certain circumstances. 'Delegates are typed properly', I interpreted as meaning for one thing (besides fixing the unsoundness issues) that the 'immutable'/'const' qualifiers can be used on nested functions/delegate literals, which then restores the current behaviour in the case of immutable (i.e. only immutable state can be accessed through context pointers thus annotated.), and would prevent updates to data in the context in the case of const.
Re: Understanding switch + foreach
On 04/08/2014 05:14 PM, Steven Schveighoffer wrote: On Mon, 07 Apr 2014 18:30:30 -0400, Matej Nanut wrote: Hello, I don't understand why so many break statements are needed in this construct: immutable key = 3; switch (key) { foreach (c; TypeTuple!(1, 2, 3, 4, 5)) { case c: "Found %s!".writefln(c); break; } break; // Default always gets executed without this break. default: "Not found %s :(".writefln(key); break; } One after each case and another one after the foreach. First, let me say this is a cool usage of compile-time foreach, I had never thought of that. ... I do this quite often. Second, I think the issue is likely a bug with the break exiting the wrong scope. No, this is expected behaviour. break and continue work in any foreach statement. break always breaks the innermost breakable statement. (In particular, it does not pair up with case statements.) You may be able to fix it by labeling the switch scope. For example: theswitch: switch(key) { ... break theswitch; // should exit the switch. } I have not tested it. -Steve Yes, this works.
Re: Understanding switch + foreach
On 04/17/2014 03:15 PM, Steven Schveighoffer wrote: But should a foreach over a tuple a breakable statement? Well, it is a foreach statement. It is on the other hand not too clear what to do about 'static foreach', but I am leaning towards banning non-labelled break and continue inside it. Basically, the above seems to me it should be equivalent to: case 1: writefln("Found %s!", 1); break; case 2: writefln("Found %s!", 2); break; ... The foreach should be gone once the foreach is executed at compile-time. ... So are the break statements. The lowering is more along the lines of: { case 1: writefln("Found %s!", 1); goto Lbreakforeach; case 2: writefln("Found %s!", 2); goto Lbreakforeach; } Lbreakforeach:; If the break breaks the foreach, why isn't just case 1 produced? That would be an actual break in the foreach, no? -Steve No. You don't know the dynamic behaviour of the code at runtime just by unrolling the foreach body. import std.stdio; alias Seq(T...)=T; void main(){ int x,y,z; readf("%d %d %d",&x,&y,&z); alias a=Seq!(x,y,z); auto b=[x,y,z]; foreach(v;a){ if(v==2) break; writeln(v); } foreach(v;b){ if(v==2) break; writeln(v); } }
Re: alias this with template class?
On 06/03/2012 08:43 PM, Namespace wrote: I think this should work: [code] import std.stdio; class Foo(T) { public: T Num; @property Foo!(U) ConvertTo(U)() inout { return cast(Foo!(U)) this; } alias ConvertTo this; } void Call(const Foo!(float) FFoo) { } void main() { Foo!(ubyte) UbFoo = new Foo!(ubyte)(); Call(UbFoo); readln(); } [/code] Why it doesn't? Making this generally work as you expect would be too hard. The compiler would have to reverse-engineer the 'ConvertTo' template which is an undecidable problem in general. Some clever heuristics might suffice for most practical instances though, but those are very open-ended and therefore it is hard to incorporate them into the language definition. If you think it should be done you could file a suggestion (enhancement request) into the bug tracker.
Re: Multi-Dimensional Associative Arrays ".get" and "in"
On 06/06/2012 04:17 PM, Paul wrote: I've seen examples using .get and "in" to test for keys: aa.get("hello", "salute") == "ciao" "hello" in aa Can I use this .get function or "in" operator with multi-D arrays? string[string][string][string] aa; if (["hello"][][] in aa) ? Well, no. string[string][string][string] is an associative array mapping strings to associative arrays mapping strings to associative arrays mapping strings to strings. The indexes are more or less unrelated as far as the AA interface is concerned. You can implement such functionality yourself, or use an approach like string[Tuple!(string, string, string)] aa; if(tuple("hello","salute","ciao") in aa) if it is compatible with your usage patterns. this maps 3 key strings to the value string in one go.
Re: Is it possible to force CTFE?
On 06/10/2012 09:04 AM, Tommi wrote: 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? No there is not. You could use a template that calls a private function at compile time instead. What is your use case? 2) Is it possible to specialize a function based on whether or not the parameter that was passed in is a compile time constant? This has been discussed before, but there is not. 1-2) could be introduced later when D gets AST macros. 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); Yes, DMD/GDC/LDC should be able to do this to different extents.
Re: Auto-conversion in array literals?
On 06/12/2012 12:55 AM, bearophile wrote: This is valid Scala code: object Main { def main(args: Array[String]): Unit = { val a: List[BigInt] = List(1, BigInt(2)) } } Is it possible/meaningful to support/allow D code like this? import std.bigint; void main() { BigInt[] a = [1, BigInt(2)]; } Bye, bearophile Making it work would require a way to specify an implicit conversion from int to BigInt.
Re: Package and virtual functions
On 06/14/2012 01:34 AM, BLM768 wrote: override will eventually be required when overriding a function. It is already if you compile with -w but not yet all of the time - though since protected isn't virtual and isn't really overriding anything, the compiler doesn't complain if you don't use override with it (though it will if you do, since it's not overriding anything). So, eventually (or now if you use -w), you will _always_ know whether a function is overiding another or not, because it will have to have override if it is and can't have it if it isn't. - Jonathan M Davis That's good to know. I'll start using -w from now on. However, the problem still exists that if a function is meant to override a virtual method, but the method is not actually virtual, and the programmer forgets to type "override," the compiler won't complain and the error will slip through. True, but it will be explicit in the derived class code: No 'override', no function that is overridden.
Re: Package and virtual functions
On 06/14/2012 01:57 AM, BLM768 wrote: I guess that another solution to this whole mess is to just start requiring the use of override; then everyone would be educated and it would be obvious where the bug is in the code I posted. Since we don't want to break code, though, maybe there should be a message prominently displayed on the D homepage telling people to use the -w switch until the requirement is actually enforced for all code. If that requirement is going to be enforced, though, I can't think of a better time than now; otherwise, people are going to write code without "override" and eventually end up making the same mistakes that I did. Yes, this is the plan.
Re: Constraining template's function parameter signature
On 06/14/2012 02:57 PM, Tommi wrote: 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)) ... alias PseudoInputRange!(int, (ref int x) {++x;}) MyRange; static assert(isInputRange!MyRange); 'T.init' is not an lvalue and can therefore not be passed by ref. You can fix the problem with the fewest keystrokes like this: if (is(typeof(advance([T.init][0])) == void))
Re: How to specialize templates for l-value and non-l-value arguments?
You can overload based on 'ref'. auto just(ref immutable(T) data) { return Maybe!T(&data); } auto just(immutable(T) data) { return Maybe!T([data].ptr); }
Re: Switch Statement case '0': .. case '9'
On 06/14/2012 05:59 PM, Paul wrote: The book in section 3.5 gives these valid case examples: case ’0’: .. case ’9’: case ’A’: .. case ’Z’: case ’a’: .. case ’z’: case ’.’, ’,’, ’:’, ’;’, ’!’, ’?’: In my code: case "STEP01": ...compiles and works correct case "STEP01", "STEP02": ...compiles and works correct case "STEP01": .. case "STEP50": ...compiler reports: iccstats.d(27): Error: Integer constant expression expected instead of "STEP01" iccstats.d(27): Error: Integer constant expression expected instead of "STEP50" iccstats.d(27): Error: integral constant must be scalar type, not const(char[]) Help please. case-range expressions don't work with strings. (because there is no general way to meaningfully fill in the gap.) You could automatically generate the case statements via a string mixin (untested): mixin({ string r; foreach(i;1..51) r~=`case "STEP`~(i<10?"0":"")~to!string(i)~`":`; return r; }()); But that is probably overkill, why not just parse the string with an if statement? If you need fallthrough, you can use a goto statement if(...) goto Lstepn; switch(...){ case ...: ... break; Lstepn: case ...: ... break; }
Re: How to specialize templates for l-value and non-l-value arguments?
On 06/14/2012 06:20 PM, Roman D. Boiko wrote: On Thursday, 14 June 2012 at 16:08:54 UTC, Roman D. Boiko wrote: On Thursday, 14 June 2012 at 16:05:52 UTC, Timon Gehr wrote: You can overload based on 'ref'. auto just(ref immutable(T) data) { return Maybe!T(&data); } auto just(immutable(T) data) { return Maybe!T([data].ptr); } Great! Thanks Hmm... seems to fail for immutable: immutable a = 2.0f; #line 121 auto y0 = Maybe!float.just(a); assert(!y0.empty); assert(y0.front == a); Compiler output: fds/persistent.d(121): Error: 2 is not an lvalue dmd: glue.c:1114: virtual unsigned int Type::totym(): Assertion `0' failed. Aborted (core dumped) make: *** [build/client] Error 134 You have found a compiler bug.
Re: Immutability and other attributes, please review
On 06/14/2012 06:42 PM, Jonathan M Davis wrote: I wish that you could do auto f = new float(2.1); and therefore auto f = new immutable(float)(2.1); but you can't. This seems to be an arbitrary limitation. Imho it should be fixed. Probably it was missed because allocating a primitive type on the heap is not a very common operation.
Re: Using consistently auto as function return type
On 06/16/2012 11:31 AM, Tommi wrote: 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? auto return types make functions semantically dependent on each other, eg. the following is illegal code: auto foo(){bar(); return 0; } auto bar(){foo(); return 1; } In order to resolve the return type of foo, the body of foo needs to be analyzed, which involves resolving the return type of bar, therefore the body of bar needs to be analyzed, which involves resolving the return type of foo, therefore the body of foo needs to be analyzed, ... The current implementation is very conservative, and rejects every dependency cycle of auto return functions, even if the return types could be resolved in theory. Other than that, there are no more severe issues, I see these major applications for auto return types: - The body is very short and spells out the type explicitly, auto saves redundancy. - The implementer does not know the exact return type himself, because it depends on template arguments. - The user of the function does not need to know the return type. eg if it is a type local to the function.
Re: sorting associative array's keys by values
On 06/16/2012 06:34 PM, maarten van damme wrote: Right now I have an associative array "int[string] aa" and stored the keys in "string[] keys". Now I want to sort keys[] so that "aa[keys[0]]>aa[keys[1]]" I remember someone gave the answer to that question on stackoverflow but after some googling I couldn't find the right answer. maarten schwartzSort!(k=>aa[k])(keys);
Re: sorting associative array's keys by values
On 06/16/2012 06:41 PM, Timon Gehr wrote: On 06/16/2012 06:34 PM, maarten van damme wrote: Right now I have an associative array "int[string] aa" and stored the keys in "string[] keys". Now I want to sort keys[] so that "aa[keys[0]]>aa[keys[1]]" I remember someone gave the answer to that question on stackoverflow but after some googling I couldn't find the right answer. maarten schwartzSort!(k=>aa[k])(keys); oops. Seems like you actually want schwartzSort!(k=>aa[k],"a > b")(keys);
Re: sorting associative array's keys by values
On 06/16/2012 07:51 PM, maarten van damme wrote: For some crazy reason my program now crashes on seemingly random locations when parsing content of the form: randomname I want to extract randomname but an xml parser would be overkill so I extract it using curLine=curLine[curLine.countUntil(">")+1..$]; curLine=curLine[0..curLine.countUntil(" Possibly memory corruption. Do you use any unsafe constructs?
Re: Swap furthest element type of an array
On 06/18/2012 06:29 PM, Andrej Mitrovic wrote: I just had a need for this but couldn't find it in Phobos: import std.stdio; import std.traits; import std.range; template SwapElem(Arr, Type) { static if (isArray!(ElementType!Arr)) { static if (isDynamicArray!Arr) alias SwapElem!(ElementType!Arr, Type)[] SwapElem; else alias SwapElem!(ElementType!Arr, Type)[Arr.length] SwapElem; } else { static if (isDynamicArray!Arr) alias Type[] SwapElem; else alias Type[Arr.length] SwapElem; } } void main() { alias int[2][1] IntArr; alias SwapElem!(IntArr, float) FloatArr; writeln(typeid(FloatArr)); // float[2][1] } It doesn't handle complex declarations like "int[2]*[1]". It seems hard to do since I can't pass a naked pointer as a type to a template. Some other clever tricks would have to be used here. But it's a worthy start. If you can improve it feel free to do so. :) template SwapElem(A, E){ static if(is(A X:X[N],size_t N)) alias SwapElem!(X,E)[N] R; else static if(is(A X:X[])) alias SwapElem!(X,E)[] R; else static if(is(A X:X*)) alias SwapElem!(X,E)* R; else alias E R; alias R SwapElem; } pragma(msg, SwapElem!(int[]*[3][]*[2][]*[1][], float));
Re: Formatted input from text file
On 06/18/2012 05:11 PM, IK wrote: Hmm does your code generate a 1D `array` as a grid, bearophile? Anyway thanks, I'll compile it shortly. My own code evolved to what's below and gives a Range violation. Also I don't understand why formattedRead can't just accept a casted `opSlice.dup`, is it a bug? Yes. void main() { uint[20][20] grid; auto input_file = new MmFile("p011_input.txt"); string temp = cast(string)input_file.opSlice; formattedRead(temp, "%(%(%s %)\n%)",&grid); } IIRC formattedRead would require input similar to "[[1,2,3,4,5],[1,2,3,4,5],[1,2,3,4,5],[1,2,3,4,5],[1,2,3,4,5]]" This works: void main() { auto input_file = new MmFile("p011_input.txt"); auto text = cast(string)input_file[]; auto grid = text.splitLines.map!(_=>_.split.to!(uint[])).array; }
Re: Swap furthest element type of an array
On 06/19/2012 12:01 AM, Andrej Mitrovic wrote: On 6/18/12, Timon Gehr wrote: template SwapElem(A, E){ static if(is(A X:X[N],size_t N)) alias SwapElem!(X,E)[N] R; else static if(is(A X:X[])) alias SwapElem!(X,E)[] R; else static if(is(A X:X*)) alias SwapElem!(X,E)* R; else alias E R; alias R SwapElem; } pragma(msg, SwapElem!(int[]*[3][]*[2][]*[1][], float)); Nce! Did you just come up with this right now? :D Indeed. If you are interested, I'll make it work with qualified types as well. =)
Re: D: Unexpected output when using a delegate and EnumMembers
On 06/19/2012 04:44 PM, Travis Gockel wrote: I am clearly doing something wrong, You are not. but I have no idea what and would appreciate some insight. You have found a bug in DMD. Reduced test case that should compile: template Seq(T...){alias T Seq;} auto exec(alias a)(){return a();} void main(){ foreach(e; Seq!(0, 1)) static assert(exec!(()=>e)()==e); } You can report the bug here: http://d.puremagic.com/issues/ The 'exec' template is instantiated only once instead of two times.
Re: D: Unexpected output when using a delegate and EnumMembers
On 06/19/2012 05:08 PM, Artur Skawina wrote: Yes, it can be surprising, but I'm not convinced it's actually wrong behavior (the bug is http://d.puremagic.com/issues/show_bug.cgi?id=2043) It is not this bug. (And what is listed there is clearly wrong behaviour, because it can be used to break the type system.) Just do this: size_t c = count!(function(x, e) { return x.e == e;} )(source, e); and it will work. [1] artur [1] I don't do that new kinky lambda syntax, sorry. ;) Your embarrassment about this issue is justifiable.
Re: Does the 'with' statement affect object lifetime?
On 06/19/2012 07:51 PM, Ali Çehreli wrote: Bug? Bug.
Re: what is the difference between static method of the class, module method and static method of the module?
On 06/20/2012 09:52 PM, bearophile wrote: Alex Rønne Petersen: The static keyword has no effect on module functions, so 2 and 3 are equivalent. This problem is caused by DMD sloppyness regarding its management of attributes. A serious language doesn't accept a keyword like "static" where it has no meaning. What is a 'serious language'? interface I{ static int x=2; } // java It just causes confusion to newbies, and makes it harder to port D code across future D compilers... Bye, bearophile To be fair, it does not have no meaning. It is simply redundant, because all module scope declarations are implicitly 'static'.
Re: Allocate an Array!T on the heap?
On 06/22/2012 08:45 AM, Tobias Pankrath wrote: import std.container; struct A {}; void main() { Array!(A)* arr = new Array!(A); } yields bug.d(7): Error: template std.container.Array!(A).Array.__ctor does not match any function template declaration /usr/include/d/std/container.d(1625): Error: template std.container.Array!(A).Array.__ctor(U) if (isImplicitlyConvertible!(U,T)) cannot deduce template function from argument types !()() This seems to work: import std.container; struct A {}; void main() { auto arr = new Array!A(A.init); }
Re: const behaviour
On 06/22/2012 11:21 AM, Namespace wrote: Based to the current const discussions (once again) I wanted to appease my curiosity and want to ask why the following code works as described in the comments: [code] import std.stdio; class Bar { } class Foo { private: string _text; Bar _b; public: this(string text, Bar b) { this._text = text; this._b = b; } // const_behaviour.d(18): Error: cannot implicitly convert expression (this._b) of type const(Bar) to const_behaviour.Bar Bar GetB() const pure nothrow { /// <- must be const(Bar) instead of Bar return this._b; } string GetText() const pure nothrow { /// <- no const(string) is neccessary. Why? return this._text; } } void main() { Bar b = new Bar(); Foo f = new Foo("foobar", b); } [/code] string is immutable(char)[] and const(immutable(char)[]) implicitly converts to immutable(char)[]. Or put differently, a string doesn't have to be const-qualified because it cannot be changed anyway.
Re: Stack overflow
On 06/22/2012 12:22 PM, Namespace wrote: I have this code: http://codepad.org/vz17iZrm And as long as i comment out the assert's in the constructor on line 10 and the assert in the invariant on line 16 it works as i want. But otherwise the compiler prints stackoverflow and that's all. Why and how is the stack overflowed with an simple assert?! On my machine it is the compiler that crashes => compiler bug. Presumably it is having trouble with the circular alias this. (BTW, what is 'obj' in the invariant supposed to refer to?)
Re: const behaviour
On 06/22/2012 12:25 PM, Namespace wrote: As far as i know "int" is not immutable or const by default. So, why work this code: [code] import std.stdio; class Bar { } class Foo { private: int _id; Bar _b; public: this(int id, Bar b) { this._id = id; this._b = b; } // const_behaviour.d(18): Error: cannot implicitly convert expression (this._b) of type const(Bar) to const_behaviour.Bar const(Bar) GetB() const pure nothrow { /// <- must be const(Bar) instead of Bar return this._b; } int GetId() const pure nothrow { /// <- no const(int) is neccessary. Why?! return this._id; } } void main() { Bar b = new Bar(); Foo f = new Foo(42, b); } [/code] The same reason, because const(int) implicitly converts to int. If the data is copied, the qualifiers can be changed in any way that is desired. As string, int has no mutable indirections.
Re: Address of TLS variables
On 06/23/2012 09:51 PM, Alex Rønne Petersen wrote: Hi, Does taking the address of a TLS variable and passing it to other threads have defined semantics? I would assume it results in a pointer to the thread's instance of the TLS variable (which makes sense), I'd assume that it results in a pointer to the original thread's TLS variable, because threads usually share the physical address space. but is passing it to other threads OK? I think you could pass a T* function() thunk that takes the respective TLS variable's address instead, if that makes sense. Does the language guarantee this? No, it is probably implementation/architecture dependent.
Re: Stack overflow
On 06/24/2012 12:37 PM, David wrote: Am 24.06.2012 11:35, schrieb Namespace: A non-nullable type _will_ be added to Phobos at some point. As struct or class or as built-in type? And can me explain somebody why [code] @disable this(typeof(null)); [/code] print "Stack overflow"? What should typeof(null) return you? void*, int* typeof(null) gives typeof(null).
Re: Stack overflow
On 06/25/2012 02:48 AM, Jonathan M Davis wrote: On Sunday, June 24, 2012 19:03:17 Namespace wrote: This might work: this(U)(U obj) if(is(U : T)&& !is(U == typeof(null))) { } - Jonathan M Davis Interesting. With or wihtout that, if i add a method to Foo it prints "Stack overflow" also. http://dpaste.dzfl.pl/91dad66c Can you explain that? Wait, you have a template mixin inside of Foo which passes Foo to it? I don't know if you can get away with that or not, since you're trying to pass a type to a template while you're adding stuff to it via that template. So, the type is incomplete. I'm willing to be that that's your problem, but I don't know. - Jonathan M Davis This is fine. I am doing it all the time. Why are we discussing this compiler bug on the main newsgroup though?
Re: front doesn't compile for arrays of immutable data
On 06/25/2012 04:27 PM, Roman D. Boiko wrote: @property ref T front(T)(T[] a) if (!isNarrowString!(T[]) && !is(T[] == void[])) { assert(a.length, "Attempting to fetch the front of an empty array of " ~ typeof(a[0]).stringof); return a[0]; } Why is front returned by ref even when it is not possible to do so? It should always be possible to do so. What you are experiencing seems to be a compiler bug.
Re: Stack overflow
On 06/25/2012 02:18 PM, Namespace wrote: Fine. But nothing of them explain the Stack overflow if i add an additional method or disable/add an additional ctor. It does not have to be explained: it is a compiler bug.
Re: Stack overflow
On 06/25/2012 05:52 PM, Namespace wrote: On Monday, 25 June 2012 at 15:39:19 UTC, Timon Gehr wrote: On 06/25/2012 02:18 PM, Namespace wrote: Fine. But nothing of them explain the Stack overflow if i add an additional method or disable/add an additional ctor. It does not have to be explained: it is a compiler bug. Then it will take months or years until it is fixed ... too bad. Many of them get fixed quite fast if they are reported properly. And that Ref!(Foo) rf = new Foo(); ends even with "Stack overflow" and Ref!(Foo) rf2 = new Ref!(Foo)(new Foo()); not has the same explanation "Compiler Bug", hm? It is always a compiler bug if compilation crashes.
Re: Circle Calculator Help
On 06/26/2012 09:43 PM, Steven Schveighoffer wrote: On Tue, 26 Jun 2012 10:40:18 -0400, Alexander wrote: ... //Wait void wait() { writefln ("Type A to continue!"); exittest(); } //Exit tester void exittest() { char[] a; stdin.readln(a); if (a == "A") { exit(); } else { wait(); } } Hm... interesting code here :) This is not horrible, just... weird. It is functional style. ;) You probably want to avoid recursion in this case: void wait() { char[] a; while(a != "A") { writeln("Type A to continue!"); stdin.readln(a); } } -Steve I want the two examples to generate comparable code.
Re: Circle Calculator Help
On 06/27/2012 01:40 AM, Steven Schveighoffer wrote: On Tue, 26 Jun 2012 19:10:25 -0400, bearophile wrote: Steven Schveighoffer: I agree with Andrei, there is no outlet for errors in the to!T function, exception is the logical choice. Maybe I was not clear enough, so let me explain a bit better. What I don't like is to!int("15\n") to be seen as an error in the first place. I'd like it to ignore leading and trailing whitespace, as in Python (stripping it automatically): Right, but what if it's an error in your code if whitespace is present? Then you have to check for whitespace and throw your own error. I admit, that would likely be a rare occasion. But having both behaviors should be possible. ... I think the default behaviour should be the behaviour that is wanted in the majority of cases.
Re: Bug in Auto Functions and Template? Or Am I Just Crazy...
On 06/27/2012 11:07 AM, Michael wrote: Hello all, I came across some weird behaviors yesterday and I can't figure out what it's about. (1) auto factorial(int n) { if (n < 2) return 1; return n * factorial(n-1); } The compiler complained about "forward declaration of factorial". If I change the return type to int, the problem goes away. I can understand that with the recursion, it might be impossible for the compiler to deduce the type of factorial and so it compile errors, but I don't see anything about that on the Language Reference. Is this the intended behavior? Apparently the compiler attempts to type combine the types of the return statements. This does not match the language documentation. I think it should just use the type of the first return statement. (2) auto stuff(T)(T[] arr) { auto inner(T[] s) { s[0] = 0; } arr.inner(); } This time the compiler complained about 'inner' not being defined. This time I have no idea what is wrong. Thanks for your help! Michael This is expected behaviour. UFCS only works with module scope functions.
Re: Bug in Auto Functions and Template? Or Am I Just Crazy...
On 06/27/2012 01:24 PM, Timon Gehr wrote: On 06/27/2012 11:07 AM, Michael wrote: Hello all, I came across some weird behaviors yesterday and I can't figure out what it's about. (1) auto factorial(int n) { if (n < 2) return 1; return n * factorial(n-1); } The compiler complained about "forward declaration of factorial". If I change the return type to int, the problem goes away. I can understand that with the recursion, it might be impossible for the compiler to deduce the type of factorial and so it compile errors, but I don't see anything about that on the Language Reference. Is this the intended behavior? Apparently the compiler attempts to type combine the types of the return statements. This does not match the language documentation. I think it should just use the type of the first return statement. ... http://d.puremagic.com/issues/show_bug.cgi?id=8307
Re: Removing from SList (std.container)...
On 06/27/2012 08:46 PM, Roman D. Boiko wrote: On Wednesday, 27 June 2012 at 18:26:46 UTC, Steven Schveighoffer wrote: The thing that makes SList useless is the O(n) removal. Nobody will ever use SList when they can write a replacement that has O(1) removal in 10 minutes. Do you mean something like indexed/sorted dictionary? It doesn't seem to be that easy to implement. Or some other data structure with O(1) removal? O(1) removal works quite ok for a singly linked list. eg: 1. - Add a sentinel node to the start of your list. - Represent an iterator into the list as a pointer to the predecessor of the respective node. - Removal: trivial. rebind the 'next' reference of the pointed-to node. 2. - Represent the empty list as a sentinel node with null 'next' field. - For removal of a node you own a pointer to: -- case 1: the successor is an empty list: - destroy the value, set the 'next' reference to null. -- case 2: else: - move the successor's value into the node that holds the value to be removed, bind the 'next' reference to the successor of the successor.
Re: foreach syntax
On 06/29/2012 12:47 PM, Namespace wrote: A friend of mine ask me why D's foreach isn't like C# Means, why is it like int[] arr = [1, 2, 3]; foreach (int val; arr) { foreach(val; arr) { and not foreach (int val in arr) { which it is more intuitive. To someone coming from C#, yes. I could give him no clever answer to, so maybe someone here knows the reasons. Just because. This does not matter.
Re: foreach syntax
On 06/29/2012 01:01 PM, bearophile wrote: Namespace: A friend of mine ask me why D's foreach isn't like C# In D you often omit the type: foreach (val; arr) { Using "in" is better for the human programmers. Certainly not. (except if 'human' means 'python' or 'C#'.) It is just as good as ';'. But D is largely designed to make D compilers too happy. I think Walter said that the semicolon was preferred because it simplifies the compiler/compilation a little. It does not. Parsing the statements just about the same. In fact, only 2 lines in the DMD parser implementation need to be changed (slightly!) to implement the 'in' syntax instead.
Re: foreach syntax
On 06/29/2012 04:16 PM, bearophile wrote: Timon Gehr: Just because. This does not matter. Now and then I write foreach(x;y;data) error: found ';' when expecting ')' or foreach(x,y,data) or error: found ')' when expecting ';' foreach(x;y,data). error: undefined identifier y "in" avoids some of those little mistakes. foreach(x in y,data)
Re: foreach syntax
On 06/29/2012 04:23 PM, Timon Gehr wrote: ... foreach(x;y,data). error: undefined identifier y BTW, it would certainly be better if this didn't actually pass the parser.
Re: foreach syntax
On 06/29/2012 04:34 PM, bearophile wrote: Timon Gehr: foreach(x in y,data) There is no way to avoid all possible mistakes, but it's easier to mistake a ";" for a ",", than mistake a "in" for a ",". I don't think optimizing the grammar for error cases that are not even compilable code is worthwhile at all. "in" is used for this purpose in Python, C#, and probably other languages because it's more readable Probably it is used in those languages because it resembles mathematical notation, or let var in exp. I doubt there is anything deep behind it. than an arbitrary symbol like ";". Probably, but when I read code, I don't read the ';', it is just a separator and helps orientation. Making separators 'readable' is imho a non-goal. But YMMV. Patching the parser so that it accepts both forms takes 20 seconds.
Re: foreach syntax
On 06/29/2012 06:09 PM, Namespace wrote: It wasn't my intention to start a syntax war. :D But i must agree, that "in" is a lot more readable as ";". Event ":" ist more readable as ";". But i just would know the real reason to this decision. Tanks to all. :) But why correct a few guys here my code? It was more of a suggestion than a correction. foreach (int val; is the same as foreach(val; except that i like to write which type "val" is. Is that against the D nature or what? It is redundant. P.S.: Which line must be changed to allow the "in2 syntax? Just out of pure interest. Thanks. Search for TOKforeach in parse.c and change the TOKsemicolon's around there to TOKin's. If you want to allow both, that should be straightforward as well.
Re: foreach syntax
On 06/29/2012 06:27 PM, Namespace wrote: You mean just change line 3817 to if (t->value == TOKcomma || t->value == TOKsemicolon || t->value == TOKin) ? But know i have to rebuild dmd (i use windows), and i never did this before. :/ You'll also have to change the line that says expect(TOKsemicolon);
Re: foreach syntax
On 06/29/2012 07:47 PM, Namespace wrote: On Friday, 29 June 2012 at 17:08:36 UTC, Namespace wrote: Which is easy. Even on Windows? :O I tried with win32.mak in src/dmd and i get a dmd.exe. But the compiler still says "found 'in' when expecting ';'!" if i try to write foreach (val in vals) {. Have i edit the wrong line in paste.c or fails my build? You have to edit both relevant lines.
Re: foreach syntax
On 06/29/2012 07:50 PM, Namespace wrote: You'll also have to change the line that says expect(TOKsemicolon); In what? comment out? Looking at some other parts of the parse.c source reveals that if(token.value == TOKin) nextToken(); else expect(TOKsemicolon); might get you going.
Re: How would I sort an associative array by value?
On 06/29/2012 07:52 PM, ixid wrote: Or more generally does D have a library function so I can sort one array based on sorting the contents of another? sort!"a[0]
Re: foreach syntax
On 06/29/2012 08:04 PM, Namespace wrote: On Friday, 29 June 2012 at 17:55:57 UTC, Timon Gehr wrote: On 06/29/2012 07:50 PM, Namespace wrote: You'll also have to change the line that says expect(TOKsemicolon); In what? comment out? Looking at some other parts of the parse.c source reveals that if(token.value == TOKin) nextToken(); else expect(TOKsemicolon); might get you going. I think i'm to stupid for that, sry. My bad: Replacing the line with the following, together with the other change you made, works: if(token.value == TOKin) nextToken(); else check(TOKsemicolon);
Re: foreach syntax
On 06/29/2012 08:18 PM, Namespace wrote: My bad: Replacing the line with the following, together with the other change you made, works: if(token.value == TOKin) nextToken(); else check(TOKsemicolon); Impressive, thanks a lot, sometimes I'm a bit stupid. :) Last question: It works fine, but i'm getting now "DMD v2.059 DEBUG" if i compile. Do I need a special flag by recompiling? I don't have a windows system handy, but you could try the following: make -fwin32.mak release
Re: foreach syntax
On 06/29/2012 09:51 PM, Namespace wrote: But there is no overhead or something else _if_ i put the type, or? There is a slight typing and compilation overhead. Nothing significant.
Re: foreach syntax
On 06/29/2012 10:02 PM, Roman D. Boiko wrote: On Friday, 29 June 2012 at 19:52:33 UTC, Timon Gehr wrote: On 06/29/2012 09:51 PM, Namespace wrote: But there is no overhead or something else _if_ i put the type, or? There is a slight typing and compilation overhead. Nothing significant. You missed a slight reading overhead. Good catch.
Re: Debugging compiler crashes?
On 07/02/2012 08:38 PM, Wouter Verhelst wrote: Hi, I have a body of code which makes the compiler frontend segfault. Is there some automated tool which will help me produce a minimal testcase so I can file a bugreport? The body in question is fairly large, just posting that to a bugreport doesn't sound like a good idea to me. Thanks, https://github.com/CyberShadow/DustMite
Re: Parser generator?
On 07/04/2012 11:41 PM, Jonathan M Davis wrote: On Wednesday, July 04, 2012 15:32:16 Wouter Verhelst wrote: Jonathan M Davis writes: On Wednesday, July 04, 2012 14:53:02 Wouter Verhelst wrote: Hi folks, Does someone know of a parser generator for D? If it doesn't exist, I can write a parser by hand, but having it generated (at least for my initial permutation) seems like a better idea... Thanks, https://github.com/PhilippeSigaud/Pegged https://github.com/PhilippeSigaud/Pegged/wiki Whoa. That's so perfect, it makes me drool. Yeah. It's pretty cool. It really shows up D's metaprogramming capabilities. The one thing to watch out for though is that such metaprogramming tends to eat up a lot of memory when compiling at this point (primarily because the compiler doesn't manage memory very well at this point - it's approach is very simplistic). So, that may or may not cause you problems. It should be fixed eventually, but it does sometimes cause problems with this sort of thing. std.regex has similar issues. - Jonathan M Davis https://github.com/PhilippeSigaud/Pegged/wiki/Grammars-as-D-Modules
Re: why is string not implicit convertable to const(char*) ?
On 07/05/2012 09:32 PM, dcoder wrote: Thanks for the thorough explanation, but it begs the question why not make strings be array of chars that have \0 at the end of it? Because that is inefficient. It disables string slicing and is completely redundant. BTW: String literals are guaranteed to be zero-terminated. Since, lots of D programmers were/are probably C/C++ programmers, why should D be different here? Because it is a superior model. Wouldn't it facilitate more C/C++ programmers to come to D? Why would that matter?
Re: why is string not implicit convertable to const(char*) ?
On 07/06/2012 02:57 AM, Wouter Verhelst wrote: Jonathan M Davis writes: On Thursday, July 05, 2012 21:32:11 dcoder wrote: Thanks for the thorough explanation, but it begs the question why not make strings be array of chars that have \0 at the end of it? Since, lots of D programmers were/are probably C/C++ programmers, why should D be different here? Wouldn't it facilitate more C/C++ programmers to come to D? Just curious. Are you serious? I'm shocked to hear anyone suggest that. Zero-terminated strings are one of the largest mistakes in programming history. They're insanely inefficient. In fact, IIRC Walter Bright has stated that he thinks that having arrays without a length property was C's greatest mistake (and if they'd had that, they wouldn't have created zero-terminated strings). C++ tried to fix it with std::string, but C compatability bites you everywhere with that, so it only halfway works. C++ programmers in general would probably have thought that the designers of D were idiots if they had gone with zero- terminated strings. You don't do what another language did just to match. You do it because what they did works and you have no reason to change it. Zero-terminated strings were a horrible idea, and we're not about to copy it. To be fair, there are a _few_ areas in which zero-terminated strings may possibly outperform zero-terminated strings (appending data in the case where you know the memory block is large enough, for instance). It is impossible to know that the memory block is large enough unless the length of the string is known. But it isn't. But they're far and few between, and it would indeed be silly to switch to zero-terminated strings. There is no string manipulation that is significantly faster with zero-terminated strings.
Re: why is string not implicit convertable to const(char*) ?
On 07/06/2012 03:40 AM, Wouter Verhelst wrote: Timon Gehr writes: On 07/06/2012 02:57 AM, Wouter Verhelst wrote: To be fair, there are a _few_ areas in which zero-terminated strings may possibly outperform zero-terminated strings (appending data in the case where you know the memory block is large enough, for instance). It is impossible to know that the memory block is large enough unless the length of the string is known. But it isn't. Sure it is, but not by looking at the string itself. Say you have a string that contains some data you need, and some other data you don't. I.e., you want to throw out parts of the string. You could allocate a memory block that's as large as the original string (so you're sure you've got enough space), and then start memcpy'ing stuff into the new memory block from the old string. This incurs the cost of determining the original string's length, which is higher than computing the new string length for the data&length representation. This way you're sure you won't overrun your zero-terminated string, and you'll be a slight bit faster than you would be with a bounded string. Are you talking about differences of a few operations that are completely hidden on a modern out-of-order CPU? I don't think the zero-terminated string method will even perform less operations. I'll readily admit I haven't don't this all that often, though :-) But they're far and few between, and it would indeed be silly to switch to zero-terminated strings. There is no string manipulation that is significantly faster with zero-terminated strings. Correct -- but only because you said "significantly". I meant to say, 'measurably'.
Re: Garbage Collection Pitfall in C++ but not in D?
On 07/06/2012 05:39 PM, Alex Rønne Petersen wrote: On 06-07-2012 16:07, Denis Shelomovskij wrote: 06.07.2012 17:43, akaz пишет: Hi, Reading about the C++11, I stumbled upon this: http://www2.research.att.com/~bs/C++0xFAQ.html#gc-abi Specifically (quote): int* p = new int; p+=10; // ... collector may run here ... p-=10; *p = 10; // can we be sure that the int is still there? How does the D garbage collector solves (answers) that? Thank you. If you are interested in D read this first: http://dlang.org/garbage.html You can find there e.g.: > Do not add or subtract an offset to a pointer such that the result points outside of the bounds of the garbage collected object originally allocated. So `p+=10;` is already "undefined behavior". I'll just add: Handling this case is basically impossible to do sanely. You can't really know what some pointer off the bounds of a managed memory region is based on. It could literally be based on any memory region in the entire program. You could do heuristics of course, but . . . You could run the program in a dedicated VM. :)
Re: multiple inheritance
On 07/08/2012 07:31 PM, Namespace wrote: How can i implement C++ behaviour like this: class Shape : Drawable, Transformable { class Sprite : Drawable { class Image : Transformable { ? One way is to declare Transformable or Drawable as interface. But what if i have more then one class which implements Transformable/Drawable and i wouldn't rewrite the implementation of Transformable/Drawable in every class again? Depending on what exactly your use case is, this might get you going: class Shape : Drawable { protected class MyTransformable : Transformable{ // ... // (can reference all fields of the enclosing class object) } Transformable transformable; alias transformable this; this() { transformable = new MyTransformable(); } // ... }
Re: multiple inheritance
On 07/08/2012 07:47 PM, Namespace wrote: Smart idea. Why the inner class and not direct Transformable _t; ? If it should be true multiple inheritance, the class must be able to override the virtual methods of each superclass and each overridden method must be given access to the fields of the class.
Re: Portable way to obtain member function pointer (and invoke it)?
On 07/08/2012 09:57 PM, Alex Rønne Petersen wrote: Hi, Is there a portable way to obtain a pointer to a member function and invoke it with the this reference? I seem to recall some discussion about this on the NG in the past, but can't find the thread now. auto mptr = function(Base o,Args args)=>o.member(args); mptr(this, args);
Re: Return type inference on template
On 07/10/2012 04:14 PM, Andrea Fontana wrote: Simple template: T test(T)() { return T.init; } This code give error: int myVar; myVar = test(); Why? Can't compiler guess T == int? Type deduction only proceeds in the direction the data flows. Reversing this process would in principle work in a few cases, such as the one you present here. I think it would be neat to have more powerful IFTI. An even more important improvement would be to allow parameters to cross-talk, eg: auto map(R,S,T...)(R range, S delegate(ElementType!R) dg) { ... } [1,2,3].map(x=>2*x); // currently an error, but could be made to work Note that full type inference cannot be achieved in D, because the type system is Turing complete.
Re: Compilation failure
On 07/08/2012 11:47 PM, Lemonfiend wrote: Hi, I seem to have run into a strange error.. When I put tmp1 outside the main loop, it compiles fine and gives the expected output. When tmp1 is put inside the main loop, the compiler seems to get stuck in a loop? I've tested it on: http://dlang.org/index.html See error on bottom (lol) #!/usr/bin/rdmd import std.stdio; //immutable int[] tmp1 = [1, 2]; // compiles void main() { immutable int[] tmp1 = [1, 2]; // does not compile int[tmp1.length] tmp2 = tmp1; tmp2[] += 1; writeln(tmp1); writeln(tmp2); } I'd argue that this is a bug. The length of an immutable variable with a constant initializer should be a constant expression. Presumably this is caused by the compiler rewriting the array literal into an allocation.
Re: readonly?
On 07/11/2012 12:58 AM, Ali Çehreli wrote: On 07/10/2012 03:53 PM, Namespace wrote: const(T)* ? Example? class Bar {} class Foo { const(Bar) * _b; void SetBar(const(Bar) * b) { _b = b; } } void main() { auto b = new Bar(); auto f = new Foo(); f.SetBar(&b); } Ali This escapes a stack reference.
Re: Compilation failure
On 07/11/2012 04:25 AM, ixid wrote: in some way it sees global immutables almost as enums This seems like a bad idea. Consistency of behaviour would seem to be a good principle to expect of a language. You are right; this is a bug.
Re: (a,b,c) syntax
On 07/11/2012 02:44 PM, Andrea Fontana wrote: Why this code print "five" ? writeln(("One", 10, "Five")); What does ( ... , ... , ...) means? , is the comma operator inherited from C. a,b means: execute a first, then b, and the result is b.
Re: caller trouble
On 07/14/2012 08:53 AM, captaindet wrote: i need a discreet handle on the calling/instantiating source file (module). using __FILE__, it is surprisingly easy for functions (via argument) and templated functions (via template parameter) but i cannot get it working for templated classes. how can i make them aware of the calling module? thx, det module other; string fun(string infile = __FILE__){ return infile; } string tfun(string infile = __FILE__)(){ return infile; } class tclass(string infile = __FILE__){ string from = infile; } //...// module main; import other; void main(){ auto _fun = fun();//_fun == "main.d" auto _tfun = tfun();//_tfun == "main.d" auto _tclass = new tclass!();//_tclass.from == "other.d" !!! //this works but i do not want to provide __FILE__ explicitly: auto _tclassx = new tclass!(__FILE__)();//_tclass.from == "main.d" //and why do i get 2 different results for the last 2 cases? } This is a bug. dlang.org agrees: http://dlang.org/template.html#TemplateValueParameter
Re: ufcs and integer params
On 07/15/2012 05:40 AM, Jonathan M Davis wrote: On Sunday, July 15, 2012 05:30:55 Jay Norwood wrote: I see from this other discussions that it looks like 2.059 ( or maybe 2.060) does support something like 3.cm(). Not sure from the discussion if it would also accept 3.cm as in the xtext/xtend example. http://forum.dlang.org/thread/smoniukqfxerutqrj...@forum.dlang.org UFCS (universal function call syntax) was added in 2.059. If cm is a function, then 3.cm() will work. If it's a property function, then 3.cm will work. If you don't compile with -property, then 3.cm will still work with cm being a non-property function, but -property will become the normal behavior eventually, so you shouldn't expect that 3.cm will work long term unless cm is a property function. I expect it to stay. Another reason why @property-'enforcement' is flawed: @property auto cm(int arg){ .. } cm=2; // ok 2.cm; // ok The two code snippets would in fact be equivalent. What is enforced here? Why would it matter if anything is 'enforced'?
Re: ufcs and integer params
On 07/15/2012 09:41 PM, Jonathan M Davis wrote: On Sunday, July 15, 2012 11:56:57 Jonathan M Davis wrote: What is enforced here? Why would it matter if anything is 'enforced'? If you marked it as a property, then it's supposed to be abstracting a variable and should be treated as one, just like if it's a normal function, it should be invoked as a function, just like ++ shouldn't suddenly do --, and / shouldn't *. And on a purely objective note, if you don't have property enforcement, you can't turn a property function into a variable, because even though it's supposed to be used as one, you can't guarantee that everyone's using it that way, and if they're using it as a function, changing the property into a variable will break their code. And part of the point of properties is to be able to switch between variables and property functions depending on whether additional protections or calculations or whatnot are required for that variable/property. Property enforcement is required in order to allow that. - Jonathan M Davis No it is not, assuming that property enforcement is supposed to mean that function 'foo' cannot be called like 'foo' if it is not annotated @property. There is no objective argument for banning this, except that the syntax would be made free for alternative use. @property means: always implicitly call if it can be called without arguments. If it cannot, disallow calls that are not of the form fun = argument; (After the op= operators have been properly rewritten.) And that is completely sufficient for transparently switching between variable/property. Stuff that is *not* annotated @property has no relevance.
Re: ufcs and integer params
On 07/15/2012 08:56 PM, Jonathan M Davis wrote: On Sunday, July 15, 2012 19:50:18 Timon Gehr wrote: On 07/15/2012 05:40 AM, Jonathan M Davis wrote: On Sunday, July 15, 2012 05:30:55 Jay Norwood wrote: I see from this other discussions that it looks like 2.059 ( or maybe 2.060) does support something like 3.cm(). Not sure from the discussion if it would also accept 3.cm as in the xtext/xtend example. http://forum.dlang.org/thread/smoniukqfxerutqrj...@forum.dlang.org UFCS (universal function call syntax) was added in 2.059. If cm is a function, then 3.cm() will work. If it's a property function, then 3.cm will work. If you don't compile with -property, then 3.cm will still work with cm being a non-property function, but -property will become the normal behavior eventually, so you shouldn't expect that 3.cm will work long term unless cm is a property function. I expect it to stay. Another reason why @property-'enforcement' is flawed: @property auto cm(int arg){ .. } cm=2; // ok 2.cm; // ok The two code snippets would in fact be equivalent. @property isn't perfect, and I admit that the fact that both cm = 2 and 2.cm works here is undesirable, given what's trying to be done here, but it makes sense given that it's abstracting a variable. It's just undesirable that you can't make it so that it functions only as a getter. cm=2 is in fact a getter call. I don't mind this, because I don't need to write that code if I don't want to. The 'puritanical' view is simply incompatible with how the whole thing is laid out. But the overall situation is still a whale of a lot better than the laxity of letting just any function be called with or without parens depending no what each particular programmer feels like doing with it. If it's a property, it should be treated as such, and if it isn't, it shouldn't. What is enforced here? Why would it matter if anything is 'enforced'? If you marked it as a property, then it's supposed to be abstracting a variable and should be treated as one, just like if it's a normal function, it should be invoked as a function, This seems to be tautological. But what this statement presumably really meant to say was 'it should be invoked as a function using the notation present in eg. C or Java'. just like ++ shouldn't suddenly do --, and / shouldn't *. That depends entirely on the domain of these functions. I don't want to get into this argument again. Yah, we have gone through this before. The current plan is (and has been for some time) that -property will become the normal behavior, It is obvious that -property is broken and will not become the normal behaviour.
Re: ufcs and integer params
On 07/15/2012 11:11 PM, Jonathan M Davis wrote: There are two levels to enforcement. Neither exist without -property. The absolutely minimal level is that anything marked with @property must be used as a property. Without this, you can't swap out a property function for a variable without breaking code. If it means what I think it means then that should be done and this is where -property fails. The second level - i.e. strict property enforcement - also requires that non- property functions be called as functions. Exactly. This part is useless. (The 'Without this, you can't...' part is notably missing.)
Re: ufcs and integer params
On 07/15/2012 11:43 PM, Jonathan M Davis wrote: On Sunday, July 15, 2012 23:35:12 Timon Gehr wrote: The second level - i.e. strict property enforcement - also requires that non- property functions be called as functions. Exactly. This part is useless. And there, we will forever disagree. If it is a matter of personal preference, then it shouldn't be in the compiler.
Re: ufcs and integer params
On 07/15/2012 11:35 PM, Jonathan M Davis wrote: On Sunday, July 15, 2012 23:29:04 Timon Gehr wrote: The current plan is (and has been for some time) that -property will become the normal behavior, It is obvious that -property is broken and will not become the normal behaviour. It is obvious that -property needs to be fixed before it becomes the normal behavior. It is _not_ obvious that it will not become the normal behavior. The -property flag was created explicitly so that its implementation could be fixed _before_ making it the normal behavior and so that programmers had time to fix their code before it become enforced. - Jonathan M Davis I'd say the -property switch is there to make the fruitless bikeshedding discussions about @property disappear. Nothing else makes sense. Its inclusion obviously has been rushed (the error message does not even follow English grammar) and it _only_ implements the one restriction that does not objectively matter.
Re: ufcs and integer params
On 07/15/2012 11:56 PM, Jonathan M Davis wrote: On Sunday, July 15, 2012 23:47:58 Timon Gehr wrote: On 07/15/2012 11:43 PM, Jonathan M Davis wrote: On Sunday, July 15, 2012 23:35:12 Timon Gehr wrote: The second level - i.e. strict property enforcement - also requires that non- property functions be called as functions. Exactly. This part is useless. And there, we will forever disagree. If it is a matter of personal preference, then it shouldn't be in the compiler. It's a matter of enforcing the correct syntax, This post seems to attempt to distract from the fact that the topic of the discussion is which syntax is correct. which the compiler does all the time. It's just that you don't think that the compiler should care in this particular case, since it hasn't cared in the past. The compiler does not and has never 'not cared'. It has to do slightly more work. This is a designed language feature, although it's a trivial one. eg. Eiffel and Scala have the same thing. The prime reason why I think it is beneficial if no more restrictions than necessary are applied is UFCS: array(map!(x=>2*x)(range)); // should be fine range.map!(x=>2*x).array; // so should this range.map!(x=>2*x)().array(); // who needs this?
Re: Can't create immutable type in template
On 07/16/2012 01:38 AM, Nick Gurrola wrote: import std.stdio; void main() { writeln(typeid(Test!int)); } template Test(T...) { alias immutable(T[0]) Test; } This prints "int" instead of "immutable(int)" like I would expect. Is this a bug, or is that what is supposed to happen? This is a known issue. http://d.puremagic.com/issues/show_bug.cgi?id=6966 The bug report also contains a simple workaround.
Re: ufcs and integer params
On 07/16/2012 10:55 AM, Chris NS wrote: Having been around long enough to remember when the ability to call "foo()" as "foo" first appeared, I feel it necessary to point out that this was *not* in fact a deliberate design, but rather a sort of "accident" that arose out of D's first attempt at properties. Afaik this first attempt was implemented roughly as designed. It is my understanding that @property was added later in order to fix the introduced ambiguities. It was the same "accident" loaded compiler release that gave us pseudo-members -- the precursors to UFCS. I still wonder how that could possibly happen. The community discovered that these things were accepted by the compiler -- which was actually against the language spec at the time -- and further that the resulting code did the intuitively correct thing. Response to the "accidents" being generally positive, it was decided to work toward making them legitimate language features. Some flavor of @property (or of a certain other proposal which was a mimicry of C# properties... I was in that camp) That would certainly be more pretty -- OTOH it is hard to think of a way to extend this to UFCS that is as natural as what happens if everything is conflated in functions. has been in the plan ever since. I find the ongoing debate/discussion of @property and -property to be... well, moot. But hey, I'm just one crazy among an army of crazies. Well, this newsgroup has the property that the stuff that is actually important is usually unilaterally agreed upon rather quickly. :o)
Re: Is this actually supposed to be legal?
On 07/17/2012 07:23 PM, Jonathan M Davis wrote: On Tuesday, July 17, 2012 14:48:32 David Nadlinger wrote: On Tuesday, 17 July 2012 at 05:24:26 UTC, Jonathan M Davis wrote: This code strikes me as being a bug: class MyBase(T) {} class MySubA : MyBase!MySubA {} class MySubB : MyBase!MySubB {} void main() {} This pattern is actually quite common in C++ code, and referred to as CRTP (curiously recurring template pattern). If you propose to kill it, Andrei is going to get mad at you. ;) Well, it certainly seems insane to me at first glance - particularly when you take compile time reflection into account, since the derived classes' definitions are now effectively recursive (so I suspect that the situation is worse in D, since C++ doesn't have conditional compliation like D does). The fact that it is allowed does not make the compiler's job significantly more complicated. It is not important if the type is passed as a template argument or referred to directly from inside the template -- the issues are the same.
Re: Is this actually supposed to be legal?
On 07/17/2012 10:50 PM, Jonathan M Davis wrote: On Tuesday, July 17, 2012 22:36:10 Timon Gehr wrote: On 07/17/2012 07:23 PM, Jonathan M Davis wrote: On Tuesday, July 17, 2012 14:48:32 David Nadlinger wrote: On Tuesday, 17 July 2012 at 05:24:26 UTC, Jonathan M Davis wrote: This code strikes me as being a bug: class MyBase(T) {} class MySubA : MyBase!MySubA {} class MySubB : MyBase!MySubB {} void main() {} This pattern is actually quite common in C++ code, and referred to as CRTP (curiously recurring template pattern). If you propose to kill it, Andrei is going to get mad at you. ;) Well, it certainly seems insane to me at first glance - particularly when you take compile time reflection into account, since the derived classes' definitions are now effectively recursive (so I suspect that the situation is worse in D, since C++ doesn't have conditional compliation like D does). The fact that it is allowed does not make the compiler's job significantly more complicated. It is not important if the type is passed as a template argument or referred to directly from inside the template -- the issues are the same. The problem is that if you have static ifs and the like in the base class which depends on compile time reflection of the derived class, you effectively have a recursive template definition. e.g. class MyBase(T) { static if(is(typeof(T.func( { int func() { return 42; } } } - Jonathan M Davis This issue is unrelated to CRTP. (also, you probably want to negate that static if condition, otherwise the code is valid and poses no challenge to a compiler.) class MyBase{ static if(!is(typeof(T.func( int func() { return 42; } } class T : MyBase { }
Re: Is this actually supposed to be legal?
On 07/18/2012 11:08 PM, monarch_dodra wrote: On Tuesday, 17 July 2012 at 23:38:04 UTC, Jonathan M Davis wrote: It's not that it makes the compiler's life hard. It's the fact that conditional compilation relies on state that doesn't exist yet. It's messed up to be checking whether an object defines something when you're in the middle of defining that object. [snip] - Jonathan M Davis Well, while you "can" do it in C++ as the "Curiously Recursive Template Pattern" (particularly popular way of implementing the singleton pattern BTW), you can't just do anything you feel like doing with it. If I remember correctly, in C++, you can't access any of T's members, or create any (stack) instances of T, or (I think) call T's any of T's static members, because "T is not correctly formed yet". Did you try anything more advanced? For example, this outright _crashes_ my (r)dmd: class MyBase(T) { int a = T.hello(); } class MySubA : MyBase!MySubA { static int hello(){return 0;} } Well, that is a bug. I'm not entirely sure how valid the comparison with C++'s CRTP is, because D's classes are actually pointer to implementation, but I think it is a safe bet that what C++ can't do, neither can D. Careful there. D allows forward references. This is all supposed to work in D. (but DMD is poor when it comes to tricky symbol lookup tasks.)
Re: Is this actually supposed to be legal?
On 07/18/2012 01:37 AM, Jonathan M Davis wrote: On Tuesday, July 17, 2012 23:11:43 Timon Gehr wrote: This issue is unrelated to CRTP. (also, you probably want to negate that static if condition, otherwise the code is valid and poses no challenge to a compiler.) It's not that it makes the compiler's life hard. It's the fact that conditional compilation relies on state that doesn't exist yet. It's messed up to be checking whether an object defines something when you're in the middle of defining that object. ... Declarations in D are declarative. There is no notion of state.
Re: Compilation failure
On 07/19/2012 12:42 AM, bearophile wrote: Timon Gehr: You are right; this is a bug. This discussion is not about an obscure language detail, it's a common situation. FWIW, I have never run across it before. So if you think this is a bug, then please Timon file it in Bugzilla. Usually bugs are reported by the guy who finds them, but here you go: http://d.puremagic.com/issues/show_bug.cgi?id=8400
Re: ~= call copy ctor?
Use std.algorithm.move if you want to avoid the copy ctor call.
Re: Compilation failure
On 07/20/2012 01:53 PM, bearophile wrote: Timon Gehr: Usually bugs are reported by the guy who finds them, but here you go: http://d.puremagic.com/issues/show_bug.cgi?id=8400 Thank you, already fixed, it seems. Even if the fix is the opposite of what I have thought (I was thinking about forbidding global immutables too to be used as compile-time constants, while this fix turns local immutables too into enums. I hope this change doesn't cause a large mess). They are not enums. They are interpretable at compile time if their initializer is interpretable at compile time. This makes sense. This is a bug fix. Similar code already works.
Re: Is "delete" really going away?
On 07/29/2012 03:03 PM, Minas Mina wrote: Having a destructor and that you know when is going to be called is VERY useful! So by removing the "delete" keyword, what happens? We won't have a way to destroy objects in a predictable way anymore? (I'm not talking about structs in any way). Thanks import std.stdio; void main(){ auto c = new class{ ~this(){writeln("destroyed!");} }; version(future) destroy(c); else clear(c); } clear is being renamed to destroy starting from the next release IIRC.
Re: template with more than one tuple parameter
On 07/28/2012 06:17 PM, Zhenya wrote: Why do not D allow templates with more than one tuple parameters,at the same time that C++11 support it: This is a gratuitous restriction. They will be supported at some point.
Re: template with more than one tuple parameter
On 07/28/2012 06:47 PM, Simen Kjaeraas wrote: On Sat, 28 Jul 2012 18:17:14 +0200, Zhenya wrote: Why do not D allow templates with more than one tuple parameters,at the same time that C++11 support it: Well, Walter implemented type tuples with automatic flattening, The lack of multiple tuple parameters is not caused by automatic flattening. However, if they are introduced, the respective templates may only ever be instantiated by IFTI. To fix this, there would maybe need to be a special syntax to separate the tuple parameters in an explicit instantiation, eg. template Seq(T...){ alias T Seq; } template Test(T..., S...){ alias T A; alias S B; } with(Test!(int,double,float)){ static assert(is(A==Seq!(int,double,float))); static assert(is(B==Seq!())); } with(Test!(int,double,,float)){ static assert(is(A==Seq!(int,double))); static assert(is(B==Seq!(float))); } with(Test!(,int,double,float)){ static assert(is(A==Seq!())); static assert(is(B==Seq!(int,double,float))); } Of course, that feels a little bolt-on. The alternative would be to accept that templates with multiple tuple parameters cannot be instantiated explicitly. ( If we want arbitrary tuple nesting, the notation could be generalized, eg like this: Seq!(Seq!(int,double)); // flattened 2-element tuple Seq!(int,double,,); // 1-element tuple of 2-element tuple Seq!(int,double,,,); // 1-element tuple of 1-element tuple of 2-element tuple Seq!(int,double,,int,double); // 2-element tuple of 2-element tuples )
Re: A few questions
On 07/27/2012 04:35 PM, bearophile wrote: But implementing good non-null types in library code is hard It is closer to impossible than to hard. (rather harder than implementing vector ops in library code on library defined vectors). I think @disable isn't enough to cover what Spec# shows good non-null types are meant to be. Non-null types in Spec# are unsound.
Re: A few questions
On 07/29/2012 06:24 PM, bearophile wrote: Timon Gehr: Non-null types in Spec# are unsound. Really? I didn't know it. Surely its non-null design looks quite refined and thought-out. But maybe as say it's not enough still. Do you have a link where it shows it's unsound? Google for "freedom before commitment". The example is in the paper. Apparently the unsoundness was recently fixed though -- the faulty assignment in question is now correctly rejected by the online Spec# compiler.
Re: Ranges and backward iteration
On 07/30/2012 01:26 AM, Andrew wrote: I have a use case where I would like to be able to pass both a forward and backward iteration of an array to a function: void foo(InputR, OutputR)(InputR i, OutputR j) if (isInputRange!InputR && isOutputRange!(OutputR, InputR)) { ... } main() { //forward: foo(a[1..n], b[1..n]); //backward: foo(retro(a[n..$]), retro(b[n..$])); //do stuff with b as it has been constructed now... } This doesn't work Works for me. This is how I test: void foo(InputR, OutputR)(InputR i, OutputR j) if (isInputRange!InputR && isOutputRange!(OutputR, InputR)){ j.put(i); } void main() { int[] a=[2,0,0,3], b=[1,2,3,4]; int n=2; foo(a[0..n], b[0..n]); assert(b==[2,0,3,4]); foo(retro(a[n..$]), retro(b[n..$])); assert(b==[2,0,0,3]); } (retro doesn't appear to return a Range, but rather an object of type "Result", which I don't understand) 'Result' implements the range interface and is a local struct of the 'retro' function. , but the intent should be clear. How do I do this? What am I missing? There doesn't seem to be a "backward iterator" equivalent in std.range. retro should do the job.