Re: Just a reminder, I'll be at GOTO next week!
On Friday, 28 September 2012 at 16:07:51 UTC, deadalnix wrote: Le 28/09/2012 07:43, Walter Bright a écrit : talking about Component Programming in D on Oct. 2. http://gotocon.com/aarhus-2012/schedule/tuesday.jsp See you there! (use promotion code brig1000 when registering and you'll get a discount) I couldn't come. But Aarhus is a really nice city. It has the most horrible city hall ever built, but otherwise this is beautiful. Been there once, visiting some friends at the university, they used to complain that the city is quite boring to live on, at least as a student.
Re: Just a reminder, I'll be at GOTO next week!
On Tuesday, 2 October 2012 at 09:22:12 UTC, Jonas Drewsen wrote: On Tuesday, 2 October 2012 at 06:24:13 UTC, Paulo Pinto wrote: On Friday, 28 September 2012 at 16:07:51 UTC, deadalnix wrote: Le 28/09/2012 07:43, Walter Bright a écrit : talking about Component Programming in D on Oct. 2. http://gotocon.com/aarhus-2012/schedule/tuesday.jsp See you there! (use promotion code brig1000 when registering and you'll get a discount) I couldn't come. But Aarhus is a really nice city. It has the most horrible city hall ever built, but otherwise this is beautiful. Been there once, visiting some friends at the university, they used to complain that the city is quite boring to live on, at least as a student. Go to Copenhagen instead - I'll buy you a beer and talk some D. That goes for Walter as well ;) /Jonas Thanks. Next time I'm in Denmark. After all I'm living in a neighbor country, in Düsseldorf. :) Copenhagen is quite nice actually. I also did visit it during the same trip. -- Paulo
Released vibe.d 0.7.8 and improved online API documentation
The new version adds support for UDP sockets and a lot of smaller improvements and fixes, for example in the Diet parser and the REST interface generator (see http://vibed.org/blog/posts/vibe-release-0.7.8 for details). Thanks for all contributions! I've also done some improvements to the API documentation*, which is generated from DMDs JSON output (with some additional processing). The documentation has full cross-linking for types. I'm planning to break this out into a separate project with support for offline documentation generation. It should be noted that the documentation processor contains a crude D type parser, because the types in DMD's JSON always come out stringified. This is necessary to get the type links and some other things working - getting an additional detailed type AST in the original JSON would be very helpful here (and much more robust). Sönke * http://vibed.org/api/
Re: Released vibe.d 0.7.8 and improved online API documentation
Hi, I am very new to this, but cannot compile/run this under Windows 7 64-bit. I tried to run an http_example with this result: c:\vibe\bin\..\source\vibe\vpm\dependency.d(117): Error: undefined identifier HEAD c:\vibe\bin\..\source\vibe\vpm\dependency.d(117): Error: constructor vibe.vpm.dependency.Version.this (string vers) is not callable using argument types (_error_) 'C:\Users\pintes\AppData\Local\Temp\.rdmd\source\vibe.cmd' is not recognized as an internal or external command, operable program or batch file. Dňa 2. 10. 2012 18:31 Sönke Ludwig wrote / napísal(a): The new version adds support for UDP sockets and a lot of smaller improvements and fixes, for example in the Diet parser and the REST interface generator (see http://vibed.org/blog/posts/vibe-release-0.7.8 for details). Thanks for all contributions! I've also done some improvements to the API documentation*, which is generated from DMDs JSON output (with some additional processing). The documentation has full cross-linking for types. I'm planning to break this out into a separate project with support for offline documentation generation. It should be noted that the documentation processor contains a crude D type parser, because the types in DMD's JSON always come out stringified. This is necessary to get the type links and some other things working - getting an additional detailed type AST in the original JSON would be very helpful here (and much more robust). Sönke * http://vibed.org/api/
Re: Released vibe.d 0.7.8 and improved online API documentation
Am 10/2/2012 8:26 PM, schrieb Lubos Pintes: Hi, I am very new to this, but cannot compile/run this under Windows 7 64-bit. I tried to run an http_example with this result: Sorry, I think you checked out a bad commit on master. We just made some changes to the VPM system. Should compile again now.
Re: Component Programming in D
On Tuesday, 2 October 2012 at 21:51:45 UTC, Rene Zwanenburg wrote: On Tuesday, 2 October 2012 at 21:27:42 UTC, Andrei Alexandrescu wrote: http://www.reddit.com/r/programming/comments/10u6sk/component_programming_in_d/ Andrei John D. Cook mentions Walter's talk in his blog post at http://www.johndcook.com/blog/2012/10/02/pipelines-and-whirlpools/comment-page-1/#comment-249100 I've posted a link to this article in the comments, but it's awaiting moderation. Oops, link should of course be http://www.johndcook.com/blog/2012/10/02/pipelines-and-whirlpools/
Re: Component Programming in D
On Tuesday, 2 October 2012 at 21:27:42 UTC, Andrei Alexandrescu wrote: http://www.reddit.com/r/programming/comments/10u6sk/component_programming_in_d/ Andrei Nice article!
Re: Component Programming in D
On 10/2/12, Rene Zwanenburg renezwanenb...@gmail.com wrote: John D. Cook mentions Walter's talk in his blog post at http://www.johndcook.com/blog/2012/10/02/pipelines-and-whirlpools/comment-page-1/#comment-249100 He also mentions there might be a video coming up of the event. If that's true, yay! Nice article, too!
Re: Component Programming in D
On 10/2/12 6:14 PM, Paulo Pinto wrote: On Tuesday, 2 October 2012 at 21:27:42 UTC, Andrei Alexandrescu wrote: http://www.reddit.com/r/programming/comments/10u6sk/component_programming_in_d/ Andrei Nice article! I liked it the most of all I've read from Walter. Andrei
Re: Component Programming in D
Le 03/10/2012 00:45, Andrei Alexandrescu a écrit : On 10/2/12 6:14 PM, Paulo Pinto wrote: On Tuesday, 2 October 2012 at 21:27:42 UTC, Andrei Alexandrescu wrote: http://www.reddit.com/r/programming/comments/10u6sk/component_programming_in_d/ Andrei Nice article! I liked it the most of all I've read from Walter. Andrei Same here, this article is shared and loved as it must be !
Re: Just a reminder, I'll be at GOTO next week!
On Tue, 02 Oct 2012 08:24:27 +0200 Paulo Pinto pj...@progtools.org wrote: Been there once, visiting some friends at the university, they used to complain that the city is quite boring to live on, at least as a student. Students will say that about any city. It's the standard college excuse for getting drunk every day. Ask them what they'd like to have in the city and it's always I dunno
Re: Component Programming in D
On Tue, 02 Oct 2012 17:27:55 -0400 Andrei Alexandrescu seewebsiteforem...@erdani.org wrote: http://www.reddit.com/r/programming/comments/10u6sk/component_programming_in_d/ Excellent article!
Re: Component Programming in D
On Tuesday, October 02, 2012 17:27:55 Andrei Alexandrescu wrote: http://www.reddit.com/r/programming/comments/10u6sk/component_programming_in _d/ It's definitely the sort of article that we've needed to show what we're trying to do with ranges. - Jonathan M Davis
Re: Component Programming in D
On Tuesday, 2 October 2012 at 21:27:42 UTC, Andrei Alexandrescu wrote: http://www.reddit.com/r/programming/comments/10u6sk/component_programming_in_d/ Andrei The article contains a bug due to the pernicious behaviour of seedless reduce. This section: Just to show how flexible algorithms can be, reduce can also compute multiple values with one pass through the data (which is pretty useful for streaming data and would be expensive to save for a second pass through it). Multiple lambdas produce a tuple result, here the sum and sum of squares is computed: int[] arr = [1,2,3,4,5]; auto r = arr.reduce!((a,b) = a + b, (a,b) = a + b * b); writefln(sum = %s, sum of squares = %s, r[0], r[1]); Which prints: sum = 15, sum of squares = 55 That is the correct answer for the squares but only because 1*1 is 1. The first element of a seedless reduce does not have any operation carried out on it. If we change the array to [2,2,2,2,2] we would expect the squares sum to be 20. It's 18 because the seed element at arr[0] has no operation carried out on it.
Re: Component Programming in D
On Wed, 03 Oct 2012 03:05:08 +0200 Jonathan M Davis jmdavisp...@gmx.com wrote: On Tuesday, October 02, 2012 17:27:55 Andrei Alexandrescu wrote: http://www.reddit.com/r/programming/comments/10u6sk/component_programming_in _d/ It's definitely the sort of article that we've needed to show what we're trying to do with ranges. Yes, and also why a lot of D's features, esp its metaprogramming features, are so significant. And why most other languages, including dynamic languages, don't even come close. I think I'm starting to get a sense of the next big step, though. There are other misc improvements I'd like to see, but I think the biggest weakness our range approach faces now (even as far ahead as we are) is the effort and, arguably, boilerplate to actually create the ranges. Especially input/forward ranges: It's pretty well known and accepted (esp. to those who have created input/forward ranges) that the easiest way to make a generator is with a straight imperative function. But ranges turn the whole logic inside-out. Walking a tree can get particularly convoluted. So I think the next *big* step from here, in D3 or some other D-derived language, would be easing the creation of ranges. For example, a special low-boilerplate syntax for creating bidirectional and random-access ranges. Or for input (or maybe even forward) ranges, a C#-style compile-time transformation of a generator function into a range (With input ranges, you can technically get around needing source transformation right now in D2 using fibers, but that has too much runtime overhead to be used as a general solution).
Re: Component Programming in D
On Tuesday, 2 October 2012 at 21:27:42 UTC, Andrei Alexandrescu wrote: http://www.reddit.com/r/programming/comments/10u6sk/component_programming_in_d/ Andrei The article contains a bug due to the pernicious behaviour of seedless reduce. This section: Just to show how flexible algorithms can be, reduce can also compute multiple values with one pass through the data (which is pretty useful for streaming data and would be expensive to save for a second pass through it). Multiple lambdas produce a tuple result, here the sum and sum of squares is computed: int[] arr = [1,2,3,4,5]; auto r = arr.reduce!((a,b) = a + b, (a,b) = a + b * b); writefln(sum = %s, sum of squares = %s, r[0], r[1]); Which prints: sum = 15, sum of squares = 55 That is the correct answer for the squares sum but only because 1*1 is 1, what it's really doing here is 1 + (2 * 2) + (3 * 3) + (4 * 4) + (5 * 5) which happens to work in this case and for a + b and a - b but is otherwise broken. The first element of a seedless reduce does not have any operation carried out on it. If we change the array to [2,2,2,2,2] we would expect the squares sum to be 20. It's 18 because the seed element at arr[0] has no operation carried out on it other than the addition of the other elements to it.
Re: core.simd woes
On 02-Oct-12 06:28, F i L wrote: D has a big advantage over C/C++ here because of UFCS, in that we can write external functions that appear no different to encapsulated object methods. That combined with public-aliasing means the end-user only sees our pretty functions, but we're not sacrificing performance at all. Yeah, but it won't cover operators. If only opBinary could be defined at global scope... I think I've seen an enhancement to that end though. But even then simd types are built-in and operator overloading only works with user-defined types. -- Dmitry Olshansky
Re: It seems pure ain't so pure after all
On Monday, 1 October 2012 at 22:47:48 UTC, Timon Gehr wrote: A D compiler is also a D interpreter. I wouldn't even bother with D if this wasn't the case. A D compiler _contains_ a limited interpreter for constant expression evaluation. This has limitations such as not being able to perform IO at compile-time (there's a special pragma for that). This is merely an outgrowth of a compiler optimization technique. Now, back on topic: I agree with Jonathan - in general the compiler can't evaluate _all_ functions at-compile time due these limitations of CTFE and adding a compiler flag will make compilation times far worse than c++. Adding a function attribute adds marginal benefit over simply assigning to a static/enum variable.
Re: It seems pure ain't so pure after all
On 01/10/12 07:40, Tommi wrote: import std.stdio; int pow2(int val) pure { if (__ctfe) return 6; else return val * val; } void main() { assert(pow2(3) == 9); static assert(pow2(3) == 6); writeln(9 = 6 ... I knew it! '6' was faking it all along); readln(); } You don't need the if (__ctfe) to show this behaviour. Nor do you even need CTFE at all (though it would be a bit less obvious). You could demonstrate it in C++ too. Any code that behaves differently when compiled with -O, will do this as well. Constant folding of floating point numbers does the same thing, if the numbers are represented in the compiler in a different precision to how the machine calculates them. I believe that GCC, for example, uses very much higher precision (hundreds of bits) at compile time.
Re: __ctfe
On Tuesday, October 02, 2012 09:45:10 Don Clugston wrote: On 01/10/12 21:30, Adam D. Ruppe wrote: On Monday, 1 October 2012 at 19:22:37 UTC, Philippe Sigaud wrote: Something I wanted to ask for a long time: is there any runtime speed penalty in using __ctfe? No. What happens is when it goes to the compile the runtime code, __ctfe is a constant false, so then the optimizer can see it is obviously dead code and eliminate the branch entirely. You don't even have to use the -O switch to get this: Yes, I was VERY careful about this. The if (__ctfe) branch gets discarded at the end of the front-end. The backend never sees it. By the way, why is it not used in static if? That's what most of us would have expected (and it frequently seems to trip people up). I assume that it's due to some implementation detail of CTFE (like it doesn't really compile any functions differently for CTFE)? - Jonathan M Davis
Re: Idea: Introduce zero-terminated string specifier
On 10/1/2012 7:22 PM, Steven Schveighoffer wrote: However, we can't require an import to use a bizarre specifier, and you can't link un@safe code to a specifier, so the zstr concept is far superior in requiring the user to know what he is doing, and having the compiler enforce that. Yup. Does it make sense for Phobos to provide such a shortcut in an obscure header somewhere? Like std.cstring? Or should we just say roll your own if you need it? As a matter of principle, I really don't like gobs of Phobos functions that are literally one liners. Phobos should not become a mile wide but inch deep library of trivia. It should consist of non-trivial, useful, and relatively deep functions.
Re: dynamic library building and loading
Am Mon, 01 Oct 2012 19:18:46 +0200 schrieb Jacob Carlborg d...@me.com: On 2012-10-01 17:06, Johannes Pfau wrote: the problem is that we don't want the C main function in a shared libgdruntime.so, because you might want to use libgdruntime.so in a C/C++ app which has it's own main function. So we currently don't link in dmain2.o into the shared library and it must be included manually when linking an application. (But dmain2 also contains some stuff that really should be in libdruntime.so, so this source file should probably be split up at some time.) I'm not sure if I follow this correctly or not, but why is this needed to be handled manually? If you pass -shared to the compiler just skip linking dmain2.o, otherwise link with it. Would that work? Yes something similar would work, it's just not yet implemented. GDC should detect if we're linking against a shared druntime and then it should automatically add dmain2.o to the linker command.
Re: core.simd woes
On 7 August 2012 16:56, jerro a...@a.com wrote: That said, almost all simd opcodes are directly accessible in std.simd. There are relatively few obscure operations that don't have a representing function. The unpck/shuf example above for instance, they both effectively perform a sort of swizzle, and both are accessible through swizzle!(). They aren't. Swizzle only takes one argument, so you cant use it to select elements from two vectors. Both unpcklps and shufps take two arguments. Writing a swizzle with two arguments would be much harder. Any usages I've missed/haven't thought of; I'm all ears. The swizzle mask is analysed by the template, and it produces the best opcode to match the pattern. Take a look at swizzle, it's bloody complicated to do that the most efficient way on x86. Now imagine how complicated it would be to write a swizzle with to vector arguments. I can imagine, I'll have a go at it... it's something I considered, but not all architectures can do it efficiently. That said, a most-efficient implementation would probably still be useful on all architectures, but for cross platform code, I usually prefer to encourage people taking another approach rather than supply a function that is not particularly portable (or not efficient when ported). The reason I didn't write the DMD support yet is because it was incomplete, and many opcodes weren't yet accessible, like shuf for instance... and I just wasn't finished. Stopped to wait for DMD to be feature complete. I'm not opposed to this idea, although I do have a concern that, because there's no __forceinline in D (or macros), adding another layer of abstraction will make maths code REALLY slow in unoptimised builds. Can you suggest a method where these would be treated as C macros, and not produce additional layers of function calls? Unfortunately I can't, at least not a clean one. Using string mixins would be one way but I think no one wants that kind of API in Druntime or Phobos. Yeah, absolutely not. This is possibly the most compelling motivation behind a __forceinline mechanism that I've seen come up... ;) I'm already unhappy that std.simd produces redundant function calls. rant please please please can haz __forceinline! /rant I agree that we need that. Huzzah! :)
Re: Idea: Introduce zero-terminated string specifier
Andrej Mitrovic wrote: On 10/1/12, Piotr Szturmaj bncr...@jadamspam.pl wrote: For example C binding writers may change: extern(C) char* getstr(); to extern(C) cstring getstr(); I don't think you can reliably do that because of semantics w.r.t. passing parameters on the stack vs in registers based on whether a type is a pointer or not. I've had this sort of bug when wrapping C++ where the C++ compiler was passing a parameter in one way but the D compiler expected the parameters to be passed, simply because I tried to be clever and fake a return type. See: http://forum.dlang.org/thread/mailman.1547.1346632732.31962.d@puremagic.com#post-mailman.1557.1346690320.31962.d.gnu:40puremagic.com I think that align(1) structs that wrap a single value should be treated as its type. After all they have the same size and representation. I don't know how this works now, though.
Re: __ctfe
Jonathan M Davis jmdavisp...@gmx.com wrote in message news:mailman.477.1349164468.5162.digitalmar...@puremagic.com... By the way, why is it not used in static if? That's what most of us would have expected (and it frequently seems to trip people up). I assume that it's due to some implementation detail of CTFE (like it doesn't really compile any functions differently for CTFE)? - Jonathan M Davis Code inside static if blocks does not have to be semantically valid if it is not selected, and is discarded well before the interpreter could be invoked on it. It could be done using static if or version, but that would require duplicating the function and re-running semantic, which is less elegant and not really what you want. There is a little bit of explanation in the original bug report: http://d.puremagic.com/issues/show_bug.cgi?id=3556
Re: core.simd woes
On 8 August 2012 04:45, F i L witte2...@gmail.com wrote: Manu wrote: I'm not sure why the performance would suffer when placing it in a struct. I suspect it's because the struct causes the vectors to become unaligned, and that impacts performance a LOT. Walter has recently made some changes to expand the capability of align() to do most of the stuff you expect should be possible, including aligning structs, and propogating alignment from a struct member to its containing struct. This change might actually solve your problems... I've tried all combinations with align() before and inside the struct, with no luck. I'm using DMD 2.060, so unless there's a new syntax I'm unaware of, I don't think it's been adjusted to fix any alignment issues with SIMD stuff. It would be great to be able to wrap float4 into a struct, but for now I've come up with an easy and understandable alternative using SIMD types directly. I actually haven't had time to try out the new 2.60 alignment changes in practise yet. As a Win64 D user, I'm stuck with compilers that are forever 3-6 months out of date (2.58). _ The use cases I required to do this stuff efficiently were definitely agreed though by Walter, and to my knowledge, implemented... so it might be some other subtle details. It's possible that the intrinsic vector code-gen is hard-coded to use unaligned loads too. You might need to assert appropriate alignment, and then issue the movaps intrinsics directly, but I'm sure DMD can be fixed to emit movaps when it detects the vector is aligned = 16 bytes. [*clip* portability and cross-lane efficiency *clip*] Okay, that makes a lot of sense and is inline with what I was reading last night about FPU/SSE assembly code. However I'm also a bit confused. At some point, like in your hightmap example, I'm going to need to do arithmetic work on single vector components. Is there some sort of SSE arithmetic/shuffle instruction which uses masking that I should use to isolate and manipulate components? Well, actually, height maps are one thing that hardware SIMD units aren't intrinsically good at, because they do specifically require component-wise access. That said, there are still lots of interesting possibilities. If you're operating on a height map, for instance, rather than looping over the position vectors, fetching y from it, doing something with y (which I presume involves foreign data?), then putting it back, and repeating over the next vector... Do something like: align(16) float[as-many-as-there-are-verts] height_offsets; foreach(h; height_offsets) { // do some work to generate deltas for each vertex... } Now what you can probably do is unpack them and apply them directly to the vertex stream in a single pass: for(i = 0; i numVerts; i += 4) { four_heights = loadaps(height_offsets[i]); float4[4] heights; // do some shuffling/unpacking to result: four_heights.xyzw - height[0].y, height[1].y, height[2].y, height[3].y (fiddly, but simple enough) vertices[i + 0] += height[0]; vertices[i + 1] += height[1]; vertices[i + 2] += height[2]; vertices[i + 3] += height[3]; } ... I'm sure that could be improved, but you get the idea..? This approach should pipeline well, have reasonably low bandwidth, make good use of registers, and you can see there is no interaction between the FPU and SIMD unit. Disclaimer: I just made that up off the top of my head ;), but that illustrates the kind of approach you would usually take in efficient (and portable) SIMD code. If not, and manipulating components is just bad for performance reasons, then I've figured out a solution to my original concern. By using this code: @property @trusted pure nothrow { auto ref x(T:float4)(auto ref T v) { return v.ptr[0]; } auto ref y(T:float4)(auto ref T v) { return v.ptr[1]; } auto ref z(T:float4)(auto ref T v) { return v.ptr[2]; } auto ref w(T:float4)(auto ref T v) { return v.ptr[3]; } void x(T:float4)(ref float4 v, float val) { v.ptr[0] = val; } void y(T:float4)(ref float4 v, float val) { v.ptr[1] = val; } void z(T:float4)(ref float4 v, float val) { v.ptr[2] = val; } void w(T:float4)(ref float4 v, float val) { v.ptr[3] = val; } } This is fine if your vectors are in memory to begin with. But if you're already doing work on them, and they are in registers/local variables, this is the worst thing you can do. It's a generally bad practise, and someone who isn't careful with their usage will produce very slow code (on some platforms).
Re: core.simd woes
On 8 August 2012 07:54, F i L witte2...@gmail.com wrote: F i L wrote: Okay, that makes a lot of sense and is inline with what I was reading last night about FPU/SSE assembly code. However I'm also a bit confused. At some point, like in your hightmap example, I'm going to need to do arithmetic work on single vector components. Is there some sort of SSE arithmetic/shuffle instruction which uses masking that I should use to isolate and manipulate components? If not, and manipulating components is just bad for performance reasons, then I've figured out a solution to my original concern. By using this code: @property @trusted pure nothrow { auto ref x(T:float4)(auto ref T v) { return v.ptr[0]; } auto ref y(T:float4)(auto ref T v) { return v.ptr[1]; } auto ref z(T:float4)(auto ref T v) { return v.ptr[2]; } auto ref w(T:float4)(auto ref T v) { return v.ptr[3]; } void x(T:float4)(ref float4 v, float val) { v.ptr[0] = val; } void y(T:float4)(ref float4 v, float val) { v.ptr[1] = val; } void z(T:float4)(ref float4 v, float val) { v.ptr[2] = val; } void w(T:float4)(ref float4 v, float val) { v.ptr[3] = val; } } I am able to perform arithmetic on single components: auto vec = Vectors.float4(x, y, 0, 1); // factory vec.x += scalar; // += components again, I'll abandon this approach if there's a better way to manipulate single components, like you mentioned above. I'm just not aware of how to do that using SSE instructions alone. I'll do more research, but would appreciate any insight you can give. Okay, disregard this. I see you where talking about your function in std.simd (setY), and I'm referring to that for an example of the appropriate vector functions. _
Re: core.simd woes
On 8 August 2012 14:14, F i L witte2...@gmail.com wrote: David Nadlinger wrote: objdump, otool – depending on your OS. Hey, nice tools. Good to know, thanks! Manu: Here's the disassembly for my benchmark code earlier, isolated between StopWatch .start()/.stop() https://gist.github.com/**3294283 https://gist.github.com/3294283 Also, I noticed your std.simd.setY() function uses _blendps() op, but DMD's core.simd doesn't support this op (yet? It's there but commented out). Is there an alternative operation I can use for setY() ? I haven't considered/written an SSE2 fallback yet, but I expect some trick using shuf and/or shifts to blend the 2 vectors together will do it.
Re: core.simd woes
On 2 October 2012 05:28, F i L witte2...@gmail.com wrote: Not to resurrect the dead, I just wanted to share an article I came across concerning SIMD with Manu.. http://www.gamasutra.com/view/**feature/4248/designing_fast_** crossplatform_simd_.phphttp://www.gamasutra.com/view/feature/4248/designing_fast_crossplatform_simd_.php QUOTE: 1. Returning results by value By observing the intrisics interface a vector library must imitate that interface to maximize performance. Therefore, you must return the results by value and not by reference, as such: //correct inline Vec4 VAdd(Vec4 va, Vec4 vb) { return(_mm_add_ps(va, vb)); }; On the other hand if the data is returned by reference the interface will generate code bloat. The incorrect version below: //incorrect (code bloat!) inline void VAddSlow(Vec4 vr, Vec4 va, Vec4 vb) { vr = _mm_add_ps(va, vb); }; The reason you must return data by value is because the quad-word (128-bit) fits nicely inside one SIMD register. And one of the key factors of a vector library is to keep the data inside these registers as much as possible. By doing that, you avoid unnecessary loads and stores operations from SIMD registers to memory or FPU registers. When combining multiple vector operations the returned by value interface allows the compiler to optimize these loads and stores easily by minimizing SIMD to FPU or memory transfers. 2. Data Declared Purely Here, pure data is defined as data declared outside a class or struct by a simple typedef or define. When I was researching various vector libraries before coding VMath, I observed one common pattern among all libraries I looked at during that time. In all cases, developers wrapped the basic quad-word type inside a class or struct instead of declaring it purely, as follows: class Vec4 { ... private: __m128 xyzw; }; This type of data encapsulation is a common practice among C++ developers to make the architecture of the software robust. The data is protected and can be accessed only by the class interface functions. Nonetheless, this design causes code bloat by many different compilers in different platforms, especially if some sort of GCC port is being used. An approach that is much friendlier to the compiler is to declare the vector data purely, as follows: typedef __m128 Vec4; ENDQUOTE; The article is 2 years old, but It appears my earlier performance issue wasn't D related at all, but an issue with C as well. I think in this situation, it might be best (most optimized) to handle simd the C way by creating and alias or union of a simd intrinsic. D has a big advantage over C/C++ here because of UFCS, in that we can write external functions that appear no different to encapsulated object methods. That combined with public-aliasing means the end-user only sees our pretty functions, but we're not sacrificing performance at all. These are indeed common gotchas. But they don't necessarily apply to D, and if they do, then they should be bugged and hopefully addressed. There is no reason that D needs to follow these typical performance patterns from C. It's worth noting that not all C compilers suffer from this problem. There are many (most actually) compilers that can recognise a struct with a single member and treat it as if it were an instance of that member directly when being passed by value. It only tends to be a problem on older games-console compilers. As I said earlier. When I get back to finishing srd.simd off (I presume this will be some time after Walter has finished Win64 support), I'll go through and scrutinise the code-gen for the API very thoroughly. We'll see what that reveals. But I don't think there's any reason we should suffer the same legacy C by-value code-gen problems in D... (hopefully I won't eat those words ;)
Re: core.simd woes
On Tuesday, 2 October 2012 at 08:17:33 UTC, Manu wrote: On 7 August 2012 16:56, jerro a...@a.com wrote: That said, almost all simd opcodes are directly accessible in std.simd. There are relatively few obscure operations that don't have a representing function. The unpck/shuf example above for instance, they both effectively perform a sort of swizzle, and both are accessible through swizzle!(). They aren't. Swizzle only takes one argument, so you cant use it to select elements from two vectors. Both unpcklps and shufps take two arguments. Writing a swizzle with two arguments would be much harder. Any usages I've missed/haven't thought of; I'm all ears. I don't think it is possible to think of all usages of this, but for every simd instruction there are valid usages. At least for writing pfft, I found shuffling two vectors very useful. For, example, I needed a function that takes a small, square, power of two number of elements stored in vectors and bit-reverses them - it rearanges them so that you can calculate the new index of each element by reversing bits of the old index (for 16 elements using 4 element vectors this can actually be done using std.simd.transpose, but for AVX it was more efficient to make this function work on 64 elements). There are other places in pfft where I need to select elements from two vectors (for example, here https://github.com/jerro/pfft/blob/sine-transform/pfft/avx_float.d#L141 is the platform specific code for AVX). I don't think this are the kind of things that should be implemented in std.simd. If you wanted to implement all such operations (for example bit reversing a small array) that somebody may find useful at some time, std.simd would need to be huge, and most of it would never be used. I can imagine, I'll have a go at it... it's something I considered, but not all architectures can do it efficiently. That said, a most-efficient implementation would probably still be useful on all architectures, but for cross platform code, I usually prefer to encourage people taking another approach rather than supply a function that is not particularly portable (or not efficient when ported). One way to do it would be to do the following for every set of selected indices: go through all the two element one instruction operations, and check if any of them does exactly what you need, and use it if it does. Otherwise do something that will always work although it may not always be optimal. One option would be to use swizzle on both vectors to get each of the elements to their final index and then blend the two vectors together. For sse 1, 2 and 3 you would need to use xorps to blend them, so I guess this is one more place where you would need vector literals. Someone who knows which two element shuffling operations the platform supports could still write optimal platform specific (but portable across compilers) code this way and for others this would still be useful to some degree (the documentation should mention that it may not be very efficient, though). But I think that it would be better to have platform specific APIs for platform specific code, as I said earlier in this thread. Unfortunately I can't, at least not a clean one. Using string mixins would be one way but I think no one wants that kind of API in Druntime or Phobos. Yeah, absolutely not. This is possibly the most compelling motivation behind a __forceinline mechanism that I've seen come up... ;) I'm already unhappy that std.simd produces redundant function calls. rant please please please can haz __forceinline! /rant I agree that we need that. Huzzah! :) Walter opposes this, right? I wonder how we could convince him. There's one more thing that I wanted to ask you. If I were to add LDC support to std.simd, should I just add version(LDC) blocks to all the functions? Sounds like a lot of duplicated code...
Proposal: clean up semantics of array literals vs string literals
The problem --- String literals in D are a little bit magical; they have a trailing \0. This means that is possible to write, printf(Hello, World!\n); without including a trailing \0. This is important for compatibility with C. This trailing \0 is mentioned in the spec but only incidentally, and generally in connection with printf. But the semantics are not well defined. printf(Hello, W ~ orld!\n); Does this have a trailing \0 ? I think it should, because it improves readability of string literals that are longer than one line. Currently DMD adds a \0, but it is not in the spec. Now consider array literals. printf(['H','e', 'l', 'l','o','\n']); Does this have a trailing \0 ? Currently DMD does not put one in. How about ['H','e', 'l', 'l','o'] ~ World!\n ? And Hello ~ ['W','o','r','l','d','\n'] ? And Hello World! ~ '\n' ? And null ~ Hello World!\n ? Currently DMD puts \0 in some cases but not others, and it's rather random. The root cause is that this trailing zero is not part of the type, it's part of the literal. There are no rules for how literals are propagated inside expressions, they are just literals. This is a mess. There is a second difference. Array literals of char type, have completely different semantics from string literals. In module scope: char[] x = ['a']; // OK -- array literals can have an implicit .dup char[] y = b;// illegal This is a big problem for CTFE, because for CTFE, a string is just a compile-time value, it's neither string literal nor array literal! See bug 8660 for further details of the problems this causes. A proposal to clean up this mess Any compile-time value of type immutable(char)[] or const(char)[], behaves a string literals currently do, and will have a \0 appended when it is stored in the executable. ie, enum hello = ['H', 'e', 'l', 'l', 'o', '\n']; printf(hello); will work. Any value of type char[], which is generated at compile time, will not have the trailing \0, and it will do an implicit dup (as current array literals do). char [] foo() { return abc; } char [] x = foo(); // x does not have a trailing \0, and it is implicitly duped, even though it was not declared with an array literal. --- So that the difference between string literals and char array literals would simply be that the latter are polysemous. There would be no semantics associated with the form of the literal itself. We still have this oddity: void foo(char qqq = 'b') { string x = abc;// trailing \0 string y = ['a', 'b', 'c']; // trailing \0 string z = ['a', qqq, 'c']; // no trailing \0 } This is because we made the (IMHO mistaken) decision to allow variables inside array literals. This is the reason why I listed _compile time value_ in the requirement for having a \0, rather than entirely basing it on the type. We could fix that with a language change: an array literal which contains a variable should not be of immutable type. It should be of mutable type (or const, in the case where it contains other, immutable values). So char [] w = ['a', qqq, 'c']; should compile (it currently doesn't, even though w is allocated on the heap). But that's a separate proposal from the one I'm making here. I just need a decision on the main proposal so that I can fix a pile of CTFE bugs.
Re: Proposal: clean up semantics of array literals vs string literals
On Tuesday, 2 October 2012 at 11:10:46 UTC, Don Clugston wrote: The problem --- String literals in D are a little bit magical; they have a trailing \0. This means that is possible to write, printf(Hello, World!\n); without including a trailing \0. This is important for compatibility with C. This trailing \0 is mentioned in the spec but only incidentally, and generally in connection with printf. But the semantics are not well defined. printf(Hello, W ~ orld!\n); If every string literal is \0-terminated, then there should be two \0 in the final string. I guess that's not the case and that's actually my preferred behaviour, but the spec should make it crystal clear in which situations a string literal gets a terminator and in which not.
Re: Proposal: clean up semantics of array literals vs string literals
Well the whole mess come from the fact that D conflate C string and D string. The first problem come from the fact that D array are implicitly convertible to pointer. So calling D function that expect a char* is possible with D string even if it is unsafe and will not work in the general case. The fact that D provide tricks that will make it work in special cases is armful as previous discussion have shown (many D programmer assume that this will always work because of toy tests they have made, where in case it won't and toStringz must be used). The only sane solution I can think of is to : - disallow slice to convert implicitly to pointer. .ptr is made for that. - Do not put any trailing 0 in string literal, unless it is specified explicitly ( foobar\0 ). - Except if a const(char)* is expected from the string literal. In case it becomes a Cstring literal, with a trailing 0. This is made to allow uses like printf(foobar); In other terms, the receiver type is used to decide if the compiler generate a string literal or a Cstring literal. Other addition of 0 are just confusing, and will make incorrect code work in special cases, which is something you usually don't want. Code that work by accident often backfire in spectacular ways at the least expected moment.
Re: Proposal: clean up semantics of array literals vs string literals
On 10/2/12, Don Clugston d...@nospam.com wrote: A proposal to clean up this mess Any compile-time value of type immutable(char)[] or const(char)[], behaves a string literals currently do, and will have a \0 appended when it is stored in the executable. ie, enum hello = ['H', 'e', 'l', 'l', 'o', '\n']; printf(hello); will work. What about these, will these pass?: enum string x = foo; assert(x.length == 3); void test(string x) { assert(x.length == 3); } test(x); If these don't pass the proposal will break code.
Re: Getting started with D - Phobos documentation sucks
On Saturday, 29 September 2012 at 16:34:41 UTC, Andrei Alexandrescu wrote: On 9/29/12 11:30 AM, Mr. Anonymous wrote: I think documentation is really important, and something has to be done about it. How can a newcomer get started with D when he doesn't have a readable documentation of Phobos? Agree. It's high time we replace the silly litany of names at the top with a more sensible index (or, indeed, nothing at all!) Andrei That sounds great. I'm an experience developer new to D and i find the documentation quite frustrating to navigate and use. Things are kind of all over the place at the minute.
Re: Idea: Introduce zero-terminated string specifier
On 10/2/12 4:09 AM, Walter Bright wrote: On 10/1/2012 7:22 PM, Steven Schveighoffer wrote: Does it make sense for Phobos to provide such a shortcut in an obscure header somewhere? Like std.cstring? Or should we just say roll your own if you need it? As a matter of principle, I really don't like gobs of Phobos functions that are literally one liners. Phobos should not become a mile wide but inch deep library of trivia. It should consist of non-trivial, useful, and relatively deep functions. Well there are some possible reasons. Clearly useful functionality that's nontrivial deserves being abstracted in a function. On the other hand, even a short function is valuable if frequent enough and deserving of a name. We have e.g. s.strip even though it's equivalent to s.stripLeft.stripRight. Andrei
Re: Idea: Introduce zero-terminated string specifier
Le 01/10/2012 22:33, Vladimir Panteleev a écrit : On Monday, 1 October 2012 at 12:12:52 UTC, deadalnix wrote: Le 01/10/2012 13:29, Vladimir Panteleev a écrit : On Monday, 1 October 2012 at 10:56:36 UTC, deadalnix wrote: How does to!string know that the string is 0 terminated ? By convention (it doesn't). It is unsafe as hell oO Forcing the programmer to put strlen calls everywhere in his code is not any safer. I make the library safer. If the programmer manipulate unsafe construct (like c strings) it is up to the programmer to ensure safety, not the lib.
Re: Proposal: clean up semantics of array literals vs string literals
On 02/10/12 14:02, Andrej Mitrovic wrote: On 10/2/12, Don Clugston d...@nospam.com wrote: A proposal to clean up this mess Any compile-time value of type immutable(char)[] or const(char)[], behaves a string literals currently do, and will have a \0 appended when it is stored in the executable. ie, enum hello = ['H', 'e', 'l', 'l', 'o', '\n']; printf(hello); will work. What about these, will these pass?: enum string x = foo; assert(x.length == 3); void test(string x) { assert(x.length == 3); } test(x); If these don't pass the proposal will break code. Yes, they pass. The \0 is not included in the string length. It's effectively in the data segment, not in the string.
Re: Idea: Introduce zero-terminated string specifier
Le 02/10/2012 03:13, Walter Bright a écrit : On 9/30/2012 11:31 AM, deadalnix wrote: If you know that a string is 0 terminated, you can easily create a slice from it as follow : char* myZeroTerminatedString; char[] myZeroTerminatedString[0 .. strlen(myZeroTerminatedString)]; It is clean and avoid to modify the stdlib in an unsafe way. Of course, using strlen() is always going to be unsafe. But having %zs is equally unsafe for the same reason. deadalnix's example shows that adding a new format specifier %zs adds little value, but it gets much worse. Since %zs is inherently unsafe, it hides such unsafety in a commonly used library function, which will infect everything else that transitively calls writefln with unsafety. This makes %zs an unacceptable feature. Exactly my point.
Re: Proposal: clean up semantics of array literals vs string literals
On 02/10/12 13:26, deadalnix wrote: Well the whole mess come from the fact that D conflate C string and D string. The first problem come from the fact that D array are implicitly convertible to pointer. So calling D function that expect a char* is possible with D string even if it is unsafe and will not work in the general case. The fact that D provide tricks that will make it work in special cases is armful as previous discussion have shown (many D programmer assume that this will always work because of toy tests they have made, where in case it won't and toStringz must be used). The only sane solution I can think of is to : - disallow slice to convert implicitly to pointer. .ptr is made for that. - Do not put any trailing 0 in string literal, unless it is specified explicitly ( foobar\0 ). - Except if a const(char)* is expected from the string literal. In case it becomes a Cstring literal, with a trailing 0. This is made to allow uses like printf(foobar); In other terms, the receiver type is used to decide if the compiler generate a string literal or a Cstring literal. This still doesn't solve the problem of the difference between array literals and string literals (the magical implicit .dup), which is the key problem I'm trying to solve.
Re: Setting defaults to variadic template args
On 2012-10-02 15:15, Manu wrote: Is it possible? Eg: struct Event(T... = (int, float)) { void F(T...); // - should default to F(int, float) } Does anyone have any clever tricks that will work in this scenario? Some magic tuple syntax? struct Event { static if (T.length == 0) void F(int, float); else void F(T); } Perhaps? -- /Jacob Carlborg
Re: Proposal: clean up semantics of array literals vs string literals
On 02/10/12 13:18, Tobias Pankrath wrote: On Tuesday, 2 October 2012 at 11:10:46 UTC, Don Clugston wrote: The problem --- String literals in D are a little bit magical; they have a trailing \0. This means that is possible to write, printf(Hello, World!\n); without including a trailing \0. This is important for compatibility with C. This trailing \0 is mentioned in the spec but only incidentally, and generally in connection with printf. But the semantics are not well defined. printf(Hello, W ~ orld!\n); If every string literal is \0-terminated, then there should be two \0 in the final string. I guess that's not the case and that's actually my preferred behaviour, but the spec should make it crystal clear in which situations a string literal gets a terminator and in which not. The \0 is *not* part of the string, it lies after the string. It's as if all memory is cleared, then the string literals are copied into it, with a gap of at least one byte between each. The 'trailing 0' is not part of the literal, it's the underlying cleared memory. At least, that's how I understand it. The spec is very vague.
IndexType for ranges
If you've ever worked on a template that needs to index a range, you may have run into this problem: What is the type you should use to index an RA range? The problem may not sound like much, but it is a royal pain in the ass when trying to write wrapper ranges, such as std.algorithm.map. Shoot to low, and you may en up failing to compile code such as r[r.length - 1], because r.length is of type ulong, making the implicit down-cast illegal. Shoot to high, and the implementation itself will fail to compile: auto opIndex(ulong n) return r[n]; //cannot cast ulong to size_t You might think just use typeof(length) BUT: *you aren't even guaranteed that typeof(length) will be correct! Certain ranges, such as iota, will return a length usually of type uint, but be indexed with ulong... :/ *Infinite ranges don't have length... I'd like to propose a trait called IndexType or IndexingType. This trait would be defined as A type that can be used to safely index (or slice) a range. Here is how I would define and implement this trait: If R is a RandomAccessRange, then IndexType is the type used by opIndex. Simple enough, and I got it done and working locally, but there are 2 issues I'd like to share and inquire here: *First, if R also verifies hasLength, then writing r[r.length] should be a compile time legality: The type returned by Length must fit inside opIndex. This might sound obvious, but this restriction is . **I propose adding this extra restriction to isRandomAccess: if the range verifies $(D hasLength), then it must also be index-able by the type returned by length *Second, the idea is that IndexType should *also* be useable to slice a range. Because of this, I'd like to add two extra restrictions to isSliceable: **A sliceable range must also be indexable(RA). A range that is sliceable but not indexeable is kind of retarded anyways, since you can index doing r[n, n+1].front; **Given that R must be indexable, the type used to index the range must be compatible with slicing. These are not big changes I'm proposing, but they *may* break some existing ranges. Those ranges are arguably retarded, and these changes would enforce correctness, but they'd break none the less. I'd like some feedback if you think this trait is worth pushing? For illustration, here are three examples: // struct S1 { //Other primitives here... @property ushort length(); auto opIndex(uint); auto opSlice(ulong, ulong); } struct S2 { //Other primitives here... @property ulong length(); auto opIndex(ushort); } struct S3 { //Other primitives here... @property ushort length(); auto opIndex(ulong); auto opSlice(ushort, ushort); } // Here: *S1 would have a IndexType equal to uint. S1 would be a RandomAccessRange and verify isSliceable. *S2 would NOT be a random access range, because its length can't index it. *S3 would be a RandomAccess. it's IndexType would be ulong. It would not verify hasSlicing because it can't be sliced using IndexType.
Re: core.simd woes
On 2 October 2012 13:49, jerro a...@a.com wrote: I don't think it is possible to think of all usages of this, but for every simd instruction there are valid usages. At least for writing pfft, I found shuffling two vectors very useful. For, example, I needed a function that takes a small, square, power of two number of elements stored in vectors and bit-reverses them - it rearanges them so that you can calculate the new index of each element by reversing bits of the old index (for 16 elements using 4 element vectors this can actually be done using std.simd.transpose, but for AVX it was more efficient to make this function work on 64 elements). There are other places in pfft where I need to select elements from two vectors (for example, here https://github.com/jerro/pfft/** blob/sine-transform/pfft/avx_**float.d#L141https://github.com/jerro/pfft/blob/sine-transform/pfft/avx_float.d#L141is the platform specific code for AVX). I don't think this are the kind of things that should be implemented in std.simd. If you wanted to implement all such operations (for example bit reversing a small array) that somebody may find useful at some time, std.simd would need to be huge, and most of it would never be used. I was referring purely to your 2-vector swizzle idea (or useful high-level ideas in general). Not to hyper-context-specific functions :P I can imagine, I'll have a go at it... it's something I considered, but not all architectures can do it efficiently. That said, a most-efficient implementation would probably still be useful on all architectures, but for cross platform code, I usually prefer to encourage people taking another approach rather than supply a function that is not particularly portable (or not efficient when ported). One way to do it would be to do the following for every set of selected indices: go through all the two element one instruction operations, and check if any of them does exactly what you need, and use it if it does. Otherwise do something that will always work although it may not always be optimal. One option would be to use swizzle on both vectors to get each of the elements to their final index and then blend the two vectors together. For sse 1, 2 and 3 you would need to use xorps to blend them, so I guess this is one more place where you would need vector literals. Someone who knows which two element shuffling operations the platform supports could still write optimal platform specific (but portable across compilers) code this way and for others this would still be useful to some degree (the documentation should mention that it may not be very efficient, though). But I think that it would be better to have platform specific APIs for platform specific code, as I said earlier in this thread. Yeah, I have some ideas. Some permutations are obvious, the worst-case fallback is also obvious, but there are a lot of semi-efficient in-between cases which could take a while to identify and test. It'll be a massive block of static-if code to be sure ;) Unfortunately I can't, at least not a clean one. Using string mixins would be one way but I think no one wants that kind of API in Druntime or Phobos. Yeah, absolutely not. This is possibly the most compelling motivation behind a __forceinline mechanism that I've seen come up... ;) I'm already unhappy that std.simd produces redundant function calls. rant please please please can haz __forceinline! /rant I agree that we need that. Huzzah! :) Walter opposes this, right? I wonder how we could convince him. I just don't think he's seen solid undeniable cases where it's necessary. There's one more thing that I wanted to ask you. If I were to add LDC support to std.simd, should I just add version(LDC) blocks to all the functions? Sounds like a lot of duplicated code... Go for it. And yeah, just add another version(). I don't think it can be done without blatant duplication. Certainly not without __forceinline anyway, and even then I'd be apprehensive to trust the code-gen of intrinsics wrapped in inline wrappers. That file will most likely become a nightmarish bloated mess... but that's the point of libraries ;) .. It's best all that horrible munge-ing for different architectures/compilers is put in one place and tested thoroughly, than to not provide it and allow an infinite variety of different implementations to appear. What we may want to do in the future is to split the different compilers/architectures into readable sub-modules, and public include the appropriate one based on version logic from std.simd... but I wouldn't want to do that until the API has stabilised.
Re: Setting defaults to variadic template args
module program; import std.stdio; import std.traits; import std.typetuple; struct Event (T...) { alias EraseAll!(void, TypeTuple!(T, Select!(T.length 1, int, void), Select!(T.length 2, float, void), )) T2; void F (T2 args) { writeln(typeid(typeof(args))); } } void main () { Event!() e1; e1.F(5, 6); } On Tuesday, 2 October 2012 at 13:15:08 UTC, Manu wrote: Is it possible? Eg: struct Event(T... = (int, float)) { void F(T...); // - should default to F(int, float) } Does anyone have any clever tricks that will work in this scenario? Some magic tuple syntax?
Re: Setting defaults to variadic template args
On 2 October 2012 16:24, Andrej Mitrovic andrej.mitrov...@gmail.com wrote: On 10/2/12, Manu turkey...@gmail.com wrote: Does anyone have any clever tricks that will work in this scenario? Some magic tuple syntax? Without resorting to helper templates I only know of using this internal trick: struct Event(Args...) { static if (Args.length) alias Args T; else alias TypeTuple!(int, float) T; void F(T t) { } } Also there's a somewhat related bug but for variadic template functions with default arguments: http://d.puremagic.com/issues/show_bug.cgi?id=8687 I think this is fine for my needs. Thanks!
Re: LDC blacklisted in Ubuntu
On 09/27/2012 12:02 PM, Joseph Rushton Wakeling wrote: I'd love to, but it would be irresponsible to commit to it as (right now especially) I don't have a very good idea of what time I'll be able to offer. Just to follow up here -- a couple of days ago I pulled LDC from GitHub and built it. First time I've tried LDC in a while as up until fairly recently I was not aware of the work on GitHub. Very nice and friendly build process -- I like the inclusion of druntime and phobos as submodules. The executables produced are nice and fast -- maybe about 10-15% slower than GDC for the number-crunching code I tested, but much faster than dmd-compiled programs, and the compilation process itself is super-fast. I'll try and follow up in about 6 weeks' time by which time I should be settled in new job. If it's all all right time-wise, and if someone can mentor me in production of good-quality deb files, I'd be willing to reconsider the maintainer issue. :-)
Re: Setting defaults to variadic template args
Or maybe... This seems like a much better solution: module program; import std.stdio; import std.traits; import std.typetuple; template SelectTrue (bool condition, T) { static if (condition) alias T SelectTrue; } struct Event (T...) { alias TypeTuple!(T, SelectTrue!(T.length 1, int), SelectTrue!(T.length 2, float), ) T2; void F (T2 args) { writeln(typeid(typeof(args))); } } void main () { Event!() e1; e1.F(5, 6); } On Tuesday, 2 October 2012 at 13:44:10 UTC, luka8088 wrote: module program; import std.stdio; import std.traits; import std.typetuple; struct Event (T...) { alias EraseAll!(void, TypeTuple!(T, Select!(T.length 1, int, void), Select!(T.length 2, float, void), )) T2; void F (T2 args) { writeln(typeid(typeof(args))); } } void main () { Event!() e1; e1.F(5, 6); } On Tuesday, 2 October 2012 at 13:15:08 UTC, Manu wrote: Is it possible? Eg: struct Event(T... = (int, float)) { void F(T...); // - should default to F(int, float) } Does anyone have any clever tricks that will work in this scenario? Some magic tuple syntax?
Re: Proposal: clean up semantics of array literals vs string literals
2012/10/2 Don Clugston d...@nospam.com: The problem --- String literals in D are a little bit magical; they have a trailing \0. This means that is possible to write, printf(Hello, World!\n); without including a trailing \0. This is important for compatibility with C. This trailing \0 is mentioned in the spec but only incidentally, and generally in connection with printf. But the semantics are not well defined. printf(Hello, W ~ orld!\n); Does this have a trailing \0 ? I think it should, because it improves readability of string literals that are longer than one line. Currently DMD adds a \0, but it is not in the spec. Now consider array literals. printf(['H','e', 'l', 'l','o','\n']); Does this have a trailing \0 ? Currently DMD does not put one in. How about ['H','e', 'l', 'l','o'] ~ World!\n ? And Hello ~ ['W','o','r','l','d','\n'] ? And Hello World! ~ '\n' ? And null ~ Hello World!\n ? Currently DMD puts \0 in some cases but not others, and it's rather random. The root cause is that this trailing zero is not part of the type, it's part of the literal. There are no rules for how literals are propagated inside expressions, they are just literals. This is a mess. There is a second difference. Array literals of char type, have completely different semantics from string literals. In module scope: char[] x = ['a']; // OK -- array literals can have an implicit .dup char[] y = b;// illegal This is a big problem for CTFE, because for CTFE, a string is just a compile-time value, it's neither string literal nor array literal! See bug 8660 for further details of the problems this causes. A proposal to clean up this mess Any compile-time value of type immutable(char)[] or const(char)[], behaves a string literals currently do, and will have a \0 appended when it is stored in the executable. ie, enum hello = ['H', 'e', 'l', 'l', 'o', '\n']; printf(hello); will work. Any value of type char[], which is generated at compile time, will not have the trailing \0, and it will do an implicit dup (as current array literals do). char [] foo() { return abc; } char [] x = foo(); // x does not have a trailing \0, and it is implicitly duped, even though it was not declared with an array literal. --- So that the difference between string literals and char array literals would simply be that the latter are polysemous. There would be no semantics associated with the form of the literal itself. We still have this oddity: void foo(char qqq = 'b') { string x = abc;// trailing \0 string y = ['a', 'b', 'c']; // trailing \0 string z = ['a', qqq, 'c']; // no trailing \0 } This is because we made the (IMHO mistaken) decision to allow variables inside array literals. This is the reason why I listed _compile time value_ in the requirement for having a \0, rather than entirely basing it on the type. We could fix that with a language change: an array literal which contains a variable should not be of immutable type. It should be of mutable type (or const, in the case where it contains other, immutable values). So char [] w = ['a', qqq, 'c']; should compile (it currently doesn't, even though w is allocated on the heap). But that's a separate proposal from the one I'm making here. I just need a decision on the main proposal so that I can fix a pile of CTFE bugs. Maybe your proposal is correct. I think the key idea is *polysemous typed string literal*. When based on the Ideal D Interpreter in my brain, the organized rule will become like follows. 1-1) In semantic level, D should have just one polysemous string literal, which is an array of char. 1-2) In token level, D has two represents for the polysemous string literal, they are str and ['s','t','r']. 2) The polysemous string literl is implicitly convertible to [wd]?char[] and immutable([wd]?char)[] (I think const([wd]?char)[] is not need, because immutable([wd]?char)[] is implicitly convertible to them). 3) The concatenation result between polysemous literals is still polysemous, but its representation is different based on the both side of the operator. str ~ str; // strstr str ~ ['s','t','r']; // ['s','t','r','s','t','r'] str ~ 's'; // strs ['s','t','r'] ~ 's'; // ['s','t','r','s'] str ~ null; // str ['s','t','r'] ~ null; // ['s','t','r'] 4) After semantics _and_ optimization, polysemous string literal which represented as like 4-1) str is typed as immutable([wd]?char)[] (The char type is depends on the literal suffix). 4-2) ['s','t','r'] is typed as ([wd]?char)[] (The char type is depends on the common type of its elements). 5) In object file generating phase, string literal which typed as 5-1) immutable([wd]?)char[] is stored in the executable and implicitly terminated with \0. 5-2) [wd]?char[] are stored in the executable as the
Re: Setting defaults to variadic template args
And the simplest solution wins: module program; import std.stdio; import std.traits; import std.typetuple; struct Event (T1 = int, T2 = float, Telse...) { alias TypeTuple!(T1, T2, Telse) T; void F (T args) { writeln(typeid(typeof(args))); } } void main () { Event!() e1; e1.F(5, 6); } I hope that you found the solution that you where looking for. On Tuesday, 2 October 2012 at 13:49:56 UTC, luka8088 wrote: Or maybe... This seems like a much better solution: module program; import std.stdio; import std.traits; import std.typetuple; template SelectTrue (bool condition, T) { static if (condition) alias T SelectTrue; } struct Event (T...) { alias TypeTuple!(T, SelectTrue!(T.length 1, int), SelectTrue!(T.length 2, float), ) T2; void F (T2 args) { writeln(typeid(typeof(args))); } } void main () { Event!() e1; e1.F(5, 6); } On Tuesday, 2 October 2012 at 13:44:10 UTC, luka8088 wrote: module program; import std.stdio; import std.traits; import std.typetuple; struct Event (T...) { alias EraseAll!(void, TypeTuple!(T, Select!(T.length 1, int, void), Select!(T.length 2, float, void), )) T2; void F (T2 args) { writeln(typeid(typeof(args))); } } void main () { Event!() e1; e1.F(5, 6); } On Tuesday, 2 October 2012 at 13:15:08 UTC, Manu wrote: Is it possible? Eg: struct Event(T... = (int, float)) { void F(T...); // - should default to F(int, float) } Does anyone have any clever tricks that will work in this scenario? Some magic tuple syntax?
Re: Proposal: clean up semantics of array literals vs string literals
On Tuesday, 2 October 2012 at 11:10:46 UTC, Don Clugston wrote: [SNIP] A proposal to clean up this mess [SNIP] While I think it is convenient to be able to write 'printf(world);', as you point out, I think that the fact that it works inconsistently (and by that, I mean there are rules and exceptions), is even more dangerous. If at all possible, I'd rather side with consistency, then the we got your back... except when we don't approach: IE: strings are NEVER null terminated. In theory, how often do you *really* need null terminated strings? And when you do, wouldn't it be safer to just write 'printf(world\0)'? or 'printf(str ~ world ~ '\0');' rather than Am I in a case where it is null terminated? Yeah... 90% confident I am... If you want 0 termination, then make it explicit, that's my opinion. Besides, as you said, the null termination is not documented, so anything relying on it is a bug really. Just an observation of an implementation detail.
Re: Setting defaults to variadic template args
On 2 October 2012 16:45, Manu turkey...@gmail.com wrote: On 2 October 2012 16:24, Andrej Mitrovic andrej.mitrov...@gmail.comwrote: On 10/2/12, Manu turkey...@gmail.com wrote: Does anyone have any clever tricks that will work in this scenario? Some magic tuple syntax? Without resorting to helper templates I only know of using this internal trick: struct Event(Args...) { static if (Args.length) alias Args T; else alias TypeTuple!(int, float) T; void F(T t) { } } Also there's a somewhat related bug but for variadic template functions with default arguments: http://d.puremagic.com/issues/show_bug.cgi?id=8687 I think this is fine for my needs. Thanks! Actually, this leaves a problem... Distinction between: Event x; // using defaults and Event!() x; // explicitly selecting none (which would fall back to the defaults) Is such a distinction possible? I presume not...
Re: A study on immutability usage
Interesting, I vaguely remember that Eiffel has a 'once' keyword, but I'm not sure if it could help here.
zero-terminated strings, string literals, etc
Recent discussions on the zero terminated string problems and inconsistency of string literals has me, again, wondering why D doesn't have a 'type' to represent C's zero terminated strings. It seems to me that having a type, and typing C functions with it would solve a lot of problems. The compiler could/would then error if people attempted to pass a D string without converting it correctly. The compiler would create literals with or without \0 as required by the 'type' being assigned, parameter passed, etc. The conversion function from a D string to a C string would return the new type. A %sz format specifier could be added to writef which would be able to type check the argument. As the only way to get a variable of the new type would be from a literal, conversion or C function call so we could be sure it was in fact \0 terminated(*), and so.. An implicit conversion between a C string and a D string (slice using strlen) would be possible, and safe. (Though, not at zero runtime cost) Existing (correct) code would continue to compile, by this I mean: - passing literals - calling a conversion function for each D string argument But code which passes D string variables to C functions without conversion would start to fail to compile, so the change will 'break' existing code. There would be several solutions in these cases: 1) add a call to a conversion function. Introducing a conversion cost which was not previously present. 2) re-type the variable as a C string. If it's not used for anything else then this is more correct. If it's passed to other code then because a C string will implicitly converts (with a slice/strlen) to a D string this substitution will work in most cases, however that act of conversion will incur a cost (but it can/should be one off if the result is assigned/kept). I am probably missing something obvious, or I have forgotten one of the array/slice complexities which makes this a nightmare. Thoughts? Regan (*) Ignoring buggy/broken C functions returning non-zero terminated strings.. as we will crash on these no matter what in any case. -- Using Opera's revolutionary email client: http://www.opera.com/mail/
Re: Proposal: clean up semantics of array literals vs string literals
Le 02/10/2012 15:12, Don Clugston a écrit : On 02/10/12 13:26, deadalnix wrote: Well the whole mess come from the fact that D conflate C string and D string. The first problem come from the fact that D array are implicitly convertible to pointer. So calling D function that expect a char* is possible with D string even if it is unsafe and will not work in the general case. The fact that D provide tricks that will make it work in special cases is armful as previous discussion have shown (many D programmer assume that this will always work because of toy tests they have made, where in case it won't and toStringz must be used). The only sane solution I can think of is to : - disallow slice to convert implicitly to pointer. .ptr is made for that. - Do not put any trailing 0 in string literal, unless it is specified explicitly ( foobar\0 ). - Except if a const(char)* is expected from the string literal. In case it becomes a Cstring literal, with a trailing 0. This is made to allow uses like printf(foobar); In other terms, the receiver type is used to decide if the compiler generate a string literal or a Cstring literal. This still doesn't solve the problem of the difference between array literals and string literals (the magical implicit .dup), which is the key problem I'm trying to solve. OK, infact we have 2 different and unrelated problems here. I have to say I have no idea for the second one.
Re: Proposal: clean up semantics of array literals vs string literals
On 10/2/12 7:11 AM, Don Clugston wrote: The problem --- String literals in D are a little bit magical; they have a trailing \0. [snip] I don't mean to be Debbie Downer on this because I reckon it addresses an issue that some have, although I never do. With that warning, a few candid opinions follow. First, I think zero-terminated strings shouldn't be needed frequently enough in D code to make this necessary. Second, a simple and workable solution to this would be to address the matter dynamically: make toStringz opportunistically look whether there's a \0 beyond the end of the string, EXCEPT when the string happens to end exactly at a page boundary (in which case accessing memory beyond the end of the string may produce a page fault). With this simple dynamic test we don't need precise and stringent rules for the implementation. Third, the complex set of rules proposed pushes the number of cases in which the \0 is guaranteed, but doesn't make for a clear and easy to remember boundary. Therefore people will need to remember some more rules to make sure they can, well, avoid a call to toStringz. On 10/2/12 10:55 AM, Regan Heath wrote: Recent discussions on the zero terminated string problems and inconsistency of string literals has me, again, wondering why D doesn't have a 'type' to represent C's zero terminated strings. It seems to me that having a type, and typing C functions with it would solve a lot of problems. [snip] I am probably missing something obvious, or I have forgotten one of the array/slice complexities which makes this a nightmare. You're not missing anything and defining a zero-terminated type is something I considered doing and have been highly interested in. My interest is motivated by the fact that sentinel-terminated structures are a very interesting example of forward ranges that are also contiguous. That sets them apart from both singly-linked lists and simple arrays, and gives them interesting properties. I'd be interested in defining the more general: struct SentinelTerminatedSlice(T, T terminator) { private T* data; ... } That would be a forward range and the instantiation SentinelTerminatedSlice!(char, 0) would be CString. However, so far I held off of defining such a range because C-strings are seldom useful in D code and there are not many other compelling examples of sentinel-terminated ranges. Maybe it's time to dust off that idea, I'd love it if we gathered enough motivation for it. Andrei
Re: zero-terminated strings, string literals, etc
Am 02.10.2012 16:55, schrieb Regan Heath: Recent discussions on the zero terminated string problems and inconsistency of string literals has me, again, wondering why D doesn't have a 'type' to represent C's zero terminated strings. It seems to me that having a type, and typing C functions with it would solve a lot of problems. You have basically a type only used for 0-terminated strings, char*, in D you use normally string, and if you wanna represent binary data you use ubyte[], I've never used char* except for interfacing with C. I would prefer a library soulution, some kind of Struct which is implicitly convertable to char* (0-terminates) and also to string (not 0-terminated), not sure how to implement that though.
Re: Proposal: clean up semantics of array literals vs string literals
On Tuesday, 2 October 2012 at 15:14:10 UTC, Andrei Alexandrescu wrote: However, so far I held off of defining such a range because C-strings are seldom useful in D code [...] I think your view of what is common in D code is not representative. You are primarily a library writer, which means you rarely have to interface with other code. Please correct me if I'm wrong, but I don't believe you've written much application-level D code. For people that write applications, we have the unfortunate chore of having to call lots of C APIs to get things done. There's a long list of things for which there is no D interface (graphics, audio, input, GUI, database, platform APIs, various 3rd party libs). Invariably these interfaces require C strings. In short, if you write applications in D, you need C strings. I don't know what the right decision is here, but please do not say that C-strings are seldom useful in D code.
Re: Setting defaults to variadic template args
On 10/2/12, Manu turkey...@gmail.com wrote: Actually, this leaves a problem... Distinction between: Event x; // using defaults and Event!() x; // explicitly selecting none (which would fall back to the defaults) Is such a distinction possible? I presume not... Well actually you can't use the first syntax at all with templates or templated types. :/
Re: Setting defaults to variadic template args
On 2 October 2012 18:56, Andrej Mitrovic andrej.mitrov...@gmail.com wrote: On 10/2/12, Manu turkey...@gmail.com wrote: Actually, this leaves a problem... Distinction between: Event x; // using defaults and Event!() x; // explicitly selecting none (which would fall back to the defaults) Is such a distinction possible? I presume not... Well actually you can't use the first syntax at all with templates or templated types. :/ Errr, really? If the template has default args, surely you don't need to specify any template args? I'm sure I've done that before... :/
Re: core.simd woes
Manu wrote: These are indeed common gotchas. But they don't necessarily apply to D, and if they do, then they should be bugged and hopefully addressed. There is no reason that D needs to follow these typical performance patterns from C. It's worth noting that not all C compilers suffer from this problem. There are many (most actually) compilers that can recognise a struct with a single member and treat it as if it were an instance of that member directly when being passed by value. It only tends to be a problem on older games-console compilers. As I said earlier. When I get back to finishing srd.simd off (I presume this will be some time after Walter has finished Win64 support), I'll go through and scrutinise the code-gen for the API very thoroughly. We'll see what that reveals. But I don't think there's any reason we should suffer the same legacy C by-value code-gen problems in D... (hopefully I won't eat those words ;) Thanks for the insight (and the code examples, though I've been researching SIMD best-practice in C recently). It's good to know that D should (hopefully) be able to avoid these pitfalls. On a side note, I'm not sure how easy LLVM is to build on Windows (I think I built it once a long time ago), but recent performance comparisons between DMD, LDC, and GDC show that LDC (with LLVM 3.1 auto-vectorization and not using GCC -ffast-math) actually produces on-par-or-faster binary compared to GDC, at least in my code on Linux64. SIMD in LDC is currently broken, but you might consider using that if you're having trouble keeping a D release compiler up-to-date.
Re: IndexType for ranges
On Tuesday, 2 October 2012 at 13:17:45 UTC, monarch_dodra wrote: If you've ever worked on a template that needs to index a range, you may have run into this problem: What is the type you should use to index an RA range? Forgive my ignorance. What's wrong with size_t?
Re: A study on immutability usage
On Monday, 1 October 2012 at 12:28:33 UTC, bearophile wrote: Our results from 14 Java applications indicates that 72-82% of fields are stationary programmers are sometimes forced (or voluntarily choose) to initialise fields late (i.e. after the constructor has completed). This prevents such fields from being marked final even when they are designed to be immutable. [snip] The programmer intends that every Parent has a Child and vice-versa and, furthermore, that these do not change for the life of the program. He/she has marked the eld Parent.child as nal in an eort to enforce this. However, he/she is unable to mark the eld Child.parent as nal because one object must be constructed before the other. I have noticed this myself. While the cyclic reference thing does cause this every now and then, I actually find that the main cause (in large programs) is the unavailability of the constructor arguments. For example, you want to construct system X, which needs system Y, but system Y hasn't been constructed or initialised yet. In a small program, you just pull the construction of Y before X. In a large program, construction of these things is all indirect, through factories, driven by data files, which in turn is driven by some other system. The easiest thing to do is just to make the system Y reference mutable, and set it later when you know they're both around. I also find that a lot of it is simply because it's easier to not type 'final' or 'const' :-) Immutability by default would certainly make things interesting.
Re: Setting defaults to variadic template args
On 10/2/12, Manu turkey...@gmail.com wrote: Are you sure it's not fixed? I'm sure I do it all the time... :/ Or I'm smoking some really good stuff. I'd really like to see how you do it. If not, I'll have some of that stuff you're having, thanks. :p
Re: LDC blacklisted in Ubuntu
On Tuesday, 2 October 2012 at 13:46:58 UTC, Joseph Rushton Wakeling wrote: The executables produced are nice and fast -- maybe about 10-15% slower than GDC for the number-crunching code I tested, […] Is any of the code public, in the sense that you could give e.g. me access for benchmarking purposes? We are currently using a presumably suboptimal optimization pass schedule, which for example doesn't include the auto vectorizer, but are going to switch to a new built-in pass manager soon (which uses the same pass schedule as Clang), and it would be very interesting to see its impact on performance-critical code. David
Re: LDC blacklisted in Ubuntu
On 10/02/2012 06:14 PM, David Nadlinger wrote: Is any of the code public, in the sense that you could give e.g. me access for benchmarking purposes? We are currently using a presumably suboptimal optimization pass schedule, which for example doesn't include the auto vectorizer, but are going to switch to a new built-in pass manager soon (which uses the same pass schedule as Clang), and it would be very interesting to see its impact on performance-critical code. Here you go. :-) https://github.com/WebDrake/Dregs It's surely not the best D code ever written (it possibly inherits too much from C++ in design terms), but hopefully it's still useful for your purposes.
Re: IndexType for ranges
On 2012-10-02, 18:09, Peter Alexander wrote: On Tuesday, 2 October 2012 at 13:17:45 UTC, monarch_dodra wrote: If you've ever worked on a template that needs to index a range, you may have run into this problem: What is the type you should use to index an RA range? Forgive my ignorance. What's wrong with size_t? That not all ranges use it? If the range uses int, short, byte (I wonder why they'd do it, though), using size_t will not even compile. -- Simen
Re: IndexType for ranges
On Tuesday, 2 October 2012 at 16:09:16 UTC, Peter Alexander wrote: On Tuesday, 2 October 2012 at 13:17:45 UTC, monarch_dodra wrote: If you've ever worked on a template that needs to index a range, you may have run into this problem: What is the type you should use to index an RA range? Forgive my ignorance. What's wrong with size_t? This is what happens when you use size_t: // import std.range; import std.algorithm; struct ZeroToTen { ushort first = 0; ushort last = 10; @property bool empty(){return first == last;} @property ushort front(){return first;} void popFront(){++first;} @property ushort back(){return last;} void popBack(){--last;} @property ZeroToTen save(){return this;} @property ushort length(){return cast(ushort)(last - first);} ushort opIndex(ushort n){return cast(ushort)(first + n);} } void main() { ZeroToTen ztt; static assert(hasLength!ZeroToTen); //OK: normal static assert(isRandomAccess!ZeroToTen); //Ok... But I don't like where this is going... auto r = assumeSorted(ztt); //DERP! } // \src\phobos\std\range.d(6909): Error: function main.ZeroToTen.opIndex (ushort n) is not callable using argument types (uint) \src\phobos\std\range.d(6909): Error: cannot implicitly convert expression (i) of type uint to ushort \src\phobos\std\range.d(7346): Error: template instance std.range.SortedRange!(ZeroToTen,a b) error instantiating //
Re: IndexType for ranges
On Tuesday, 2 October 2012 at 16:29:28 UTC, Simen Kjaeraas wrote: On 2012-10-02, 18:09, Peter Alexander wrote: On Tuesday, 2 October 2012 at 13:17:45 UTC, monarch_dodra wrote: If you've ever worked on a template that needs to index a range, you may have run into this problem: What is the type you should use to index an RA range? Forgive my ignorance. What's wrong with size_t? That not all ranges use it? If the range uses int, short, byte (I wonder why they'd do it, though), using size_t will not even compile. That's kind of my point. Unless there's a compelling reason not to, I'd suggest we standardise on size_t indexing (and length) and avoid this issue altogether. C++ containers have a size_type typedef. No one uses it. Let's keep things simple instead of complicating things for the sake of unwanted flexibility.
Re: IndexType for ranges
On Tuesday, 2 October 2012 at 16:44:48 UTC, monarch_dodra wrote: On Tuesday, 2 October 2012 at 16:09:16 UTC, Peter Alexander wrote: On Tuesday, 2 October 2012 at 13:17:45 UTC, monarch_dodra wrote: If you've ever worked on a template that needs to index a range, you may have run into this problem: What is the type you should use to index an RA range? Forgive my ignorance. What's wrong with size_t? This is what happens when you use size_t: http://dpaste.dzfl.pl/d95ccb14 On a side note, SortedRange is pretty bold at assuming the range is slice-able. Gonna fix that.
Re: IndexType for ranges
On Tuesday, 2 October 2012 at 16:44:48 UTC, monarch_dodra wrote: On Tuesday, 2 October 2012 at 16:09:16 UTC, Peter Alexander wrote: On Tuesday, 2 October 2012 at 13:17:45 UTC, monarch_dodra wrote: If you've ever worked on a template that needs to index a range, you may have run into this problem: What is the type you should use to index an RA range? Forgive my ignorance. What's wrong with size_t? This is what happens when you use size_t: [snip] Then don't create ranges that use ushort for indexing and length. There's no need to. To be clear, I'm suggesting that all random access ranges should use size_t, and they will not be random access ranges if they use anything else. Unless someone can give a compelling reason not to do this, I cannot see anything but benefits.
Re: IndexType for ranges
monarch_dodra wrote: On Tuesday, 2 October 2012 at 16:09:16 UTC, Peter Alexander wrote: On Tuesday, 2 October 2012 at 13:17:45 UTC, monarch_dodra wrote: If you've ever worked on a template that needs to index a range, you may have run into this problem: What is the type you should use to index an RA range? Forgive my ignorance. What's wrong with size_t? This is what happens when you use size_t: // import std.range; import std.algorithm; struct ZeroToTen { ushort first = 0; ushort last = 10; @property bool empty(){return first == last;} @property ushort front(){return first;} void popFront(){++first;} @property ushort back(){return last;} void popBack(){--last;} @property ZeroToTen save(){return this;} @property ushort length(){return cast(ushort)(last - first);} ushort opIndex(ushort n){return cast(ushort)(first + n);} } Why not use size_t or ulong as parameter? This way all smaller types will be implicitly converted. ushort opIndex(size_t n){return cast(ushort)(first + n);}
Re: IndexType for ranges
On Tuesday, October 02, 2012 18:45:50 Peter Alexander wrote: On Tuesday, 2 October 2012 at 16:29:28 UTC, Simen Kjaeraas wrote: On 2012-10-02, 18:09, Peter Alexander wrote: On Tuesday, 2 October 2012 at 13:17:45 UTC, monarch_dodra wrote: If you've ever worked on a template that needs to index a range, you may have run into this problem: What is the type you should use to index an RA range? Forgive my ignorance. What's wrong with size_t? That not all ranges use it? If the range uses int, short, byte (I wonder why they'd do it, though), using size_t will not even compile. That's kind of my point. Unless there's a compelling reason not to, I'd suggest we standardise on size_t indexing (and length) and avoid this issue altogether. C++ containers have a size_type typedef. No one uses it. Let's keep things simple instead of complicating things for the sake of unwanted flexibility. In general, all ranges _should_ use size_t for both length and indexing, but for a few range types in Phobos specifically use ulong (e.g. IIRC iota does in order to work properly with ranges or long and ulong on 32-bit systems). I see _zero_ reason to support lengths or indices smaller than size_t. Types that do that are badly designed IMHO. But we already have a precedent that you can't always assume size_t (at least for length - I'm not sure about indices - but if length can be specifically ulong and the type is random access, then its indices will need to be ulong), so unfortunately, the situation is not so simple that you can always assume size_t (even you should arguably be able to). - Jonathan M Davis
Re: IndexType for ranges
On Tuesday, 2 October 2012 at 16:48:34 UTC, Peter Alexander wrote: Then don't create ranges that use ushort for indexing and length. There's no need to. To be clear, I'm suggesting that all random access ranges should use size_t, and they will not be random access ranges if they use anything else. Unless someone can give a compelling reason not to do this, I cannot see anything but benefits. I don't know, forcing an implementer on size_t is pretty gratuitous. Why can't he be free to choose his own index type? Besides, you'll still run into the problem for ranges that use ulong, such as iota. Then what about ranges that use ulong? As those wrong too? What about iota? Wrong? // import std.range; import std.algorithm; void main() { auto r = assumeSorted(iota(0L, 1L)); //Still DERP! } // src\phobos\std\range.d(6925): Error: cannot implicitly convert expression (this._input.length()) of type ulong to uint src\phobos\std\range.d(7346): Error: template instance std.range.SortedRange!(Result,a b) error instantiating // And this time, you can't blame me for doing fishy code, it's all in phobos. The end problem is this. // struct S(R) { //... auto opIndex(some_type n) { return r[r]; } } // Regardless of what you do, you will encounter problems at the boundaries or S.opIndex. Either for calling it, because some_type is too small, either for implementing it, because some_type is too big. The fact that both uint, ulong and size_t are valid indexers for range means ANYTHING in Phobos can break. The trait I'm proposing should enable support for uint, ulong and size_t, and every other type as an added bonus.
Re: IndexType for ranges
Jonathan M Davis wrote: if length can be specifically ulong and the type is random access, then its indices will need to be ulong), so unfortunately, the situation is not so simple that you can always assume size_t (even you should arguably be able to). It seems that isRandomAccessRange doesn't check that opIndex parameter type and length() return type are the same. Do you think it should?
Re: IndexType for ranges
On Tuesday, October 02, 2012 15:17:58 monarch_dodra wrote: You might think just use typeof(length) BUT: *you aren't even guaranteed that typeof(length) will be correct! Certain ranges, such as iota, will return a length usually of type uint, but be indexed with ulong... :/ *Infinite ranges don't have length... I'd argue that that's a bug in iota. iota's length even specifically returns _IndexType_. It makes no sense for length, opIndex, or opSlice to vary in type at all. They should all use the same type (ideally size_t). The fact that it's not outright required to be size_t is bad enough (though IIRC iota had some good reasons for using ulong). These are not big changes I'm proposing, but they *may* break some existing ranges. Those ranges are arguably retarded, and these changes would enforce correctness, but they'd break none the less. I'd like some feedback if you think this trait is worth pushing? Requiring that length, opIndex, and opSlice all use the same index type would be very much the right way to go IMHO. If that's done however, I don't know if we'll really need IndexType (though it may still be a good idea to add it). In addition, I'd argue that they should require that they all be at least as large as size_t (ideally, they'd even have to be either size_t or ulong and that's it - no signed types allowed), but that may be too strict at this point given that it could break existing code that did stupid stuff like use int (which _way_ too many people seem inclined to do). - Jonathan M Davis
Re: IndexType for ranges
On Tuesday, 2 October 2012 at 16:59:38 UTC, Jonathan M Davis wrote: On Tuesday, October 02, 2012 18:45:50 Peter Alexander wrote: On Tuesday, 2 October 2012 at 16:29:28 UTC, Simen Kjaeraas wrote: On 2012-10-02, 18:09, Peter Alexander wrote: On Tuesday, 2 October 2012 at 13:17:45 UTC, monarch_dodra wrote: If you've ever worked on a template that needs to index a range, you may have run into this problem: What is the type you should use to index an RA range? Forgive my ignorance. What's wrong with size_t? That not all ranges use it? If the range uses int, short, byte (I wonder why they'd do it, though), using size_t will not even compile. That's kind of my point. Unless there's a compelling reason not to, I'd suggest we standardise on size_t indexing (and length) and avoid this issue altogether. C++ containers have a size_type typedef. No one uses it. Let's keep things simple instead of complicating things for the sake of unwanted flexibility. In general, all ranges _should_ use size_t for both length and indexing, but for a few range types in Phobos specifically use ulong (e.g. IIRC iota does in order to work properly with ranges or long and ulong on 32-bit systems). I see _zero_ reason to support lengths or indices smaller than size_t. Types that do that are badly designed IMHO. But we already have a precedent that you can't always assume size_t (at least for length - I'm not sure about indices - but if length can be specifically ulong and the type is random access, then its indices will need to be ulong), so unfortunately, the situation is not so simple that you can always assume size_t (even you should arguably be able to). - Jonathan M Davis Given your stance of I see _zero_ reason to support lengths or indices smaller than size_t and Types that do that are badly designed IMHO: Are you agreeing with my proposed type tightening? If anything, it weeds out the bad designs for which you had no wish to support, while allowing better support for those that do.
Re: IndexType for ranges
On Tuesday, October 02, 2012 19:10:53 monarch_dodra wrote: Given your stance of I see _zero_ reason to support lengths or indices smaller than size_t and Types that do that are badly designed IMHO: Are you agreeing with my proposed type tightening? If anything, it weeds out the bad designs for which you had no wish to support, while allowing better support for those that do. Ideally, only size_t would be allowed. Reality makes it so that we need ulong in some cases (e.g. iota). Given that fact, you'd ideally restrict it to size_t or ulong specfically (or at least IndexType.sizeof = size_t.sizeof). The problem is that I'm quite sure that there are plenty of programmers out there who have been using int for length and indices even though it's a horribly bad idea. It's a classic mistake. So, while requiring size_t or ulong would be great, I'd be very surprised if it didn't break a fair bit of code out there. Given that fact that and Andrei's increased resistance to potential code breakage, I don't know that we can make that change. Still, I'd try to push for it though. It's bad enough that length and indices are allowed to be something other than size_t at all, but anything smaller than size_t (including using int specifically) _will_ cause problems for those who do that, if nothing else because size_t is ulong on 64-bit systems and using int will therefore mean that code using int for length will likely break when compiled on 64-bit systems (particularly when interacting with arrays). That's probably even a good argument for why we could restrict length and indices to size_t or greater even if it might break code (since it'll generally break when compiled on 64-bit systems anyway). This sort of change is going to have to get passed Andrei though, so we'll need his buy-in no matter what we do. - Jonathan M Davis
Re: IndexType for ranges
On 10/2/12 12:45 PM, Peter Alexander wrote: On Tuesday, 2 October 2012 at 16:29:28 UTC, Simen Kjaeraas wrote: On 2012-10-02, 18:09, Peter Alexander wrote: On Tuesday, 2 October 2012 at 13:17:45 UTC, monarch_dodra wrote: If you've ever worked on a template that needs to index a range, you may have run into this problem: What is the type you should use to index an RA range? Forgive my ignorance. What's wrong with size_t? That not all ranges use it? If the range uses int, short, byte (I wonder why they'd do it, though), using size_t will not even compile. That's kind of my point. Unless there's a compelling reason not to, I'd suggest we standardise on size_t indexing (and length) and avoid this issue altogether. Yes. Unfortunately there are few, few cases in which size_t is insufficient (e.g. an input range from a file or a large iota, both on 32-bit builds). I personally think these are too few to need formal support. C++ containers have a size_type typedef. No one uses it. Agreed. Let's keep things simple instead of complicating things for the sake of unwanted flexibility. Yes. We should curb some corner cases of current range design in the direction of simplifying things. Andrei
Re: IndexType for ranges
On Tuesday, 2 October 2012 at 17:13:48 UTC, Jonathan M Davis wrote: On Tuesday, October 02, 2012 15:17:58 monarch_dodra wrote: You might think just use typeof(length) BUT: *you aren't even guaranteed that typeof(length) will be correct! Certain ranges, such as iota, will return a length usually of type uint, but be indexed with ulong... :/ *Infinite ranges don't have length... I'd argue that that's a bug in iota. iota's length even specifically returns _IndexType_. It makes no sense for length, opIndex, or opSlice to vary in type at all. They should all use the same type (ideally size_t). The fact that it's not outright required to be size_t is bad enough (though IIRC iota had some good reasons for using ulong). To be honest, I think I may have put too much stress on the details. I agree we may want to enforce they have matching types (or at least, a smart hierarchy). That wasn't the root if the reason for IndexType. The big picture issue here is writing wrapper ranges, such as AssumeSorted. Or take, or every other sweet-ass range adaptors we have in std.range. If take doesn't know how to index the sub-range, how can it properly work with ranges that always use ulong, AND at the same time, support that ranges that always use size_t (uint on x86)? Answer: It CAN'T. CAN'T CAN'T CAN'T. Keep in mind, infinite ranges don't have length, so that's out of the equation... These are not big changes I'm proposing, but they *may* break some existing ranges. Those ranges are arguably retarded, and these changes would enforce correctness, but they'd break none the less. I'd like some feedback if you think this trait is worth pushing? Requiring that length, opIndex, and opSlice all use the same index type would be very much the right way to go IMHO. If that's done however, I don't know if we'll really need IndexType (though it may still be a good idea to add it). In addition, I'd argue that they should require that they all be at least as large as size_t (ideally, they'd even have to be either size_t or ulong and that's it - no signed types allowed), but that may be too strict at this point given that it could break existing code that did stupid stuff like use int (which _way_ too many people seem inclined to do). - Jonathan M Davis You'd still need IndexType for the reasons mentioned above, unless you wanted to write auto opIndex(ParameterTypeTuple(R.opIndex)[1] n) in all your ranges. AND, you'd require the array specialization (which would default to size_t). The actual support of things smaller than size_t, at that point, would become a non-issue. Just: // static if (isRandomAccessRange!R) auto opIndex(IndexType!R n) { return r[n]; } // Clean, concise. Supports both size_t and ulong (and others).
Re: IndexType for ranges
On 10/2/12 1:07 PM, monarch_dodra wrote: I don't know, forcing an implementer on size_t is pretty gratuitous. Why can't he be free to choose his own index type? Too much freedom can be detrimental (as is in this case). Andrei
Re: IndexType for ranges
On Tuesday, October 02, 2012 19:08:59 Piotr Szturmaj wrote: Jonathan M Davis wrote: if length can be specifically ulong and the type is random access, then its indices will need to be ulong), so unfortunately, the situation is not so simple that you can always assume size_t (even you should arguably be able to). It seems that isRandomAccessRange doesn't check that opIndex parameter type and length() return type are the same. Do you think it should? Definitely. It makes no sense to be able to have a length greater than you can index (beyond the fact that the last index is length - 1), and it makes no sense to be able to index anything greater than length as far as the size of types go. - Jonathan M Davis
Re: IndexType for ranges
On Tuesday, 2 October 2012 at 17:07:19 UTC, monarch_dodra wrote: [SNIP] You know what, I think I have a better. Idea. All of this came up because I've had iota break my compiles WAY more often then I'd have liked. But I think I know of another solution. I think it would be nice if we enforced that all ranges used size_t. Everywhere. And it was enforced. I'm sorry, I like extremes.
Re: IndexType for ranges
On Tuesday, October 02, 2012 19:37:18 monarch_dodra wrote: On Tuesday, 2 October 2012 at 17:07:19 UTC, monarch_dodra wrote: [SNIP] You know what, I think I have a better. Idea. All of this came up because I've had iota break my compiles WAY more often then I'd have liked. But I think I know of another solution. I think it would be nice if we enforced that all ranges used size_t. Everywhere. And it was enforced. I'm sorry, I like extremes. Personally, I'd love that. The problem is that iota was specifically changed to use ulong to support handling long and ulong properly on 32-bit systems. Without it, you can't actually use long or ulong with a step of 1 beyond uint.max (at least, I _think_ that that was the issue). Requiring that the length and indices be size_t undermines that. Now, I have no idea how much of a problem that realistically is. After all, you can't have an array of length uint.max or 32-bit systems, so restricting iota to a length of uint.max isn't necessarily all than unreasonable IMHO. And per that argument, we _could_ change iota to use size_t again and just outright require that length and indices be size_t. - Jonathan M Davis
Re: Setting defaults to variadic template args
On 2012-10-02 18:10, Manu wrote: Are you sure it's not fixed? I'm sure I do it all the time... :/ Or I'm smoking some really good stuff. It's not needed for functions templates. But it is needed for type templates. -- /Jacob Carlborg
Re: IndexType for ranges
On Tuesday, 2 October 2012 at 17:24:32 UTC, Andrei Alexandrescu wrote: Yes. Unfortunately there are few, few cases in which size_t is insufficient (e.g. an input range from a file or a large iota, both on 32-bit builds). I personally think these are too few to need formal support. I'd throw bit arrays into the mix, where 32 bit can also be quite small. There might also be some other clever hacks using custom index types for representing non-linear data structures as ranges. The question is whether such ranges are likely to be used as random access ranges. I can't come up with a compelling use case right now, but I'd rather think twice before throwing support for them out of the window and later regretting it. Also, one of the simplest ranges (iota) not fitting the range concept has somewhat of an odd aftertaste. David
Re: Idea: Introduce zero-terminated string specifier
On Tue, 02 Oct 2012 04:09:43 -0400, Walter Bright newshou...@digitalmars.com wrote: On 10/1/2012 7:22 PM, Steven Schveighoffer wrote: Does it make sense for Phobos to provide such a shortcut in an obscure header somewhere? Like std.cstring? Or should we just say roll your own if you need it? As a matter of principle, I really don't like gobs of Phobos functions that are literally one liners. Phobos should not become a mile wide but inch deep library of trivia. It should consist of non-trivial, useful, and relatively deep functions. This, arguably, is one of the most important aspects of C to support. There are lots of C functions which provide C strings. Yes, we don't want to promote using C strings, but to have one point of conversion so you *can* use safe strings is a good thing. In other words, the sooner you convert your zero-terminated strings to char slices, the better off you are. And if we label it system code, it can't be misused in @safe code. Why support zero-terminated strings as literals if it wasn't important? You could argue that things like system calls which return zero-terminated strings are as safe to use as string literals which you know have zero terminated values. The only other alternative is to wrap those C functions with D ones that convert to char[]. I don't find this any more appealing. -Steve
Re: Idea: Introduce zero-terminated string specifier
On Tuesday, 2 October 2012 at 02:22:33 UTC, Steven Schveighoffer wrote: @system char[] zstr(char *s) { return s[0..strlen(s)]; } […] Does it make sense for Phobos to provide such a shortcut in an obscure header somewhere? Like std.cstring? Or should we just say roll your own if you need it? I didn't look it up, so I could be making quite a fool of myself right now, but doesn't to!string(char*) provide exactly that? David
openMP
Hi, I am tempted to start D programming but for me it is crucrial to be able to parallelize for-loops as can be done with openMP for C/C++ (mainly @pragma omp parallel for, @pragma omp critical). I have already seen the std.parallelism library but I'm unsure whether it can provide me with the same functionality. Thanks
Re: IndexType for ranges
On Tuesday, 2 October 2012 at 18:45:24 UTC, David Nadlinger wrote: On Tuesday, 2 October 2012 at 17:24:32 UTC, Andrei Alexandrescu wrote: Yes. Unfortunately there are few, few cases in which size_t is insufficient (e.g. an input range from a file or a large iota, both on 32-bit builds). I personally think these are too few to need formal support. I'd throw bit arrays into the mix, where 32 bit can also be quite small. There might also be some other clever hacks using custom index types for representing non-linear data structures as ranges. The question is whether such ranges are likely to be used as random access ranges. I can't come up with a compelling use case right now, but I'd rather think twice before throwing support for them out of the window and later regretting it. Also, one of the simplest ranges (iota) not fitting the range concept has somewhat of an odd aftertaste. It's easy to think of random access ranges that could easily need more than size_t: - The cartesian product of several smaller ranges - a permutationsOf(r) range - a subsetsOf(r) range Any combinatoric range would easily use up 32-bit and 64-bit indexing. If 32-bit sometimes isn't enough, then neither is 64-bit. So, the question is, do we want to allow the use of BigInt indexing?
Re: Getting started with D - Phobos documentation sucks
http://forum.dlang.org/thread/k4f4tp$8p4$1...@digitalmars.com#post-k4fdsc:24v9u:241:40digitalmars.com vibe.d got clickable types in documentation, perhaps this could be somehow integrated into phobos docs?
Re: Setting defaults to variadic template args
On 10/02/2012 03:15 PM, Manu wrote: struct Event(T... = (int, float)) { void F(T...); // - should default to F(int, float) } template Event(){alias Event!(int,float) Event;} struct Event(T...){ void F(T...); }
Re: Idea: Introduce zero-terminated string specifier
On Tue, 02 Oct 2012 15:17:42 -0400, David Nadlinger s...@klickverbot.at wrote: On Tuesday, 2 October 2012 at 02:22:33 UTC, Steven Schveighoffer wrote: @system char[] zstr(char *s) { return s[0..strlen(s)]; } […] Does it make sense for Phobos to provide such a shortcut in an obscure header somewhere? Like std.cstring? Or should we just say roll your own if you need it? I didn't look it up, so I could be making quite a fool of myself right now, but doesn't to!string(char*) provide exactly that? string is immutable. Must allocate. You fool :) just kidding, honest mistake. -Steve
Re: Idea: Introduce zero-terminated string specifier
On Tuesday, 2 October 2012 at 19:31:33 UTC, Steven Schveighoffer wrote: On Tue, 02 Oct 2012 15:17:42 -0400, David Nadlinger s...@klickverbot.at wrote: On Tuesday, 2 October 2012 at 02:22:33 UTC, Steven Schveighoffer wrote: @system char[] zstr(char *s) { return s[0..strlen(s)]; } […] Does it make sense for Phobos to provide such a shortcut in an obscure header somewhere? Like std.cstring? Or should we just say roll your own if you need it? I didn't look it up, so I could be making quite a fool of myself right now, but doesn't to!string(char*) provide exactly that? string is immutable. Must allocate. You fool :) Well, make it to!char(char*) then! ;) David
Re: Idea: Introduce zero-terminated string specifier
On Tuesday, 2 October 2012 at 19:34:31 UTC, David Nadlinger wrote: Well, make it to!char(char*) then! ;) Oh dear, this doesn't get better: Of course, I've meant to write »to!(char[])(char*)«. David
Re: openMP
On Tuesday, 2 October 2012 at 19:15:19 UTC, Farmer wrote: Hi, I am tempted to start D programming but for me it is crucrial to be able to parallelize for-loops as can be done with openMP for C/C++ (mainly @pragma omp parallel for, @pragma omp critical). I have already seen the std.parallelism library but I'm unsure whether it can provide me with the same functionality. Thanks It can. Here's an example from the docs of parallelising a simple for loop: auto logs = new double[10_000_000]; foreach(i, ref elem; taskPool.parallel(logs, 100)) { elem = log(i + 1.0); } This creates a pool of workers that each perform 100 iterations of the loop body in parallel.
Re: IndexType for ranges
On Tuesday, October 02, 2012 20:45:36 David Nadlinger wrote: On Tuesday, 2 October 2012 at 17:24:32 UTC, Andrei Alexandrescu wrote: Yes. Unfortunately there are few, few cases in which size_t is insufficient (e.g. an input range from a file or a large iota, both on 32-bit builds). I personally think these are too few to need formal support. I'd throw bit arrays into the mix, where 32 bit can also be quite small. There might also be some other clever hacks using custom index types for representing non-linear data structures as ranges. The question is whether such ranges are likely to be used as random access ranges. I can't come up with a compelling use case right now, but I'd rather think twice before throwing support for them out of the window and later regretting it. Also, one of the simplest ranges (iota) not fitting the range concept has somewhat of an odd aftertaste. If it were restricted to size_t, it would just mean that those types would be restricted to 32-bits for their length and index on 32-bit machines if you would want them to function as ranges (as iota would - if size_t is required, then it's going to use size_t, not become incompatible as a range). But it's types like this which muddy things a bit. Ideally, we'd insist that all ranges use size_t. It simplifies things and certainly using smaller than that doesn't really make sense. But if we really need to support ulong, then unfortunately, we really need to support ulong - in which case presumably length and indices would have to be size_t or ulong (either that or IndexType.sizeof = size_t.sizeof, but allowing signed types also complicates things in nasty ways). It _would_ be great to be able to just insist on size_t though. The question is whether we can reasonably get away with that. - Jonathan M Davis
Re: Idea: Introduce zero-terminated string specifier
On Tue, 02 Oct 2012 15:35:47 -0400, David Nadlinger s...@klickverbot.at wrote: On Tuesday, 2 October 2012 at 19:34:31 UTC, David Nadlinger wrote: Well, make it to!char(char*) then! ;) Oh dear, this doesn't get better: Of course, I've meant to write »to!(char[])(char*)«. Right. I agree, this should not allocate (I think someone said it does, but it's probably not necessary to). But still, what looks better? auto x = SomeSystemCallThatReturnsACString(); writefln(%s, to!(char[])(x)); writefln(%s, zstr(x)); I want something easy to type, and not too difficult to visually parse. In fact, a better solution would be to define a C string type (other than char *), and just pretend those system calls return that. Then support that C string type in writef. -Steve
Re: core.simd woes
On Tuesday, 2 October 2012 at 13:36:37 UTC, Manu wrote: On 2 October 2012 13:49, jerro a...@a.com wrote: I don't think it is possible to think of all usages of this, but for every simd instruction there are valid usages. At least for writing pfft, I found shuffling two vectors very useful. For, example, I needed a function that takes a small, square, power of two number of elements stored in vectors and bit-reverses them - it rearanges them so that you can calculate the new index of each element by reversing bits of the old index (for 16 elements using 4 element vectors this can actually be done using std.simd.transpose, but for AVX it was more efficient to make this function work on 64 elements). There are other places in pfft where I need to select elements from two vectors (for example, here https://github.com/jerro/pfft/** blob/sine-transform/pfft/avx_**float.d#L141https://github.com/jerro/pfft/blob/sine-transform/pfft/avx_float.d#L141is the platform specific code for AVX). I don't think this are the kind of things that should be implemented in std.simd. If you wanted to implement all such operations (for example bit reversing a small array) that somebody may find useful at some time, std.simd would need to be huge, and most of it would never be used. I was referring purely to your 2-vector swizzle idea (or useful high-level ideas in general). Not to hyper-context-specific functions :P My point was that those context specific functions can be implemented using a 2 vector swizzle. LLVM, for example, actually provides access to most vector shuffling instruction through shufflevector, which is basically a 2 vector swizzle.
Re: core.simd woes
On 2 October 2012 23:52, jerro a...@a.com wrote: On Tuesday, 2 October 2012 at 13:36:37 UTC, Manu wrote: On 2 October 2012 13:49, jerro a...@a.com wrote: I don't think it is possible to think of all usages of this, but for every simd instruction there are valid usages. At least for writing pfft, I found shuffling two vectors very useful. For, example, I needed a function that takes a small, square, power of two number of elements stored in vectors and bit-reverses them - it rearanges them so that you can calculate the new index of each element by reversing bits of the old index (for 16 elements using 4 element vectors this can actually be done using std.simd.transpose, but for AVX it was more efficient to make this function work on 64 elements). There are other places in pfft where I need to select elements from two vectors (for example, here https://github.com/jerro/pfft/https://github.com/jerro/pfft/** blob/sine-transform/pfft/avx_float.d#L141https://github.** com/jerro/pfft/blob/sine-**transform/pfft/avx_float.d#**L141https://github.com/jerro/pfft/blob/sine-transform/pfft/avx_float.d#L141is the platform specific code for AVX). I don't think this are the kind of things that should be implemented in std.simd. If you wanted to implement all such operations (for example bit reversing a small array) that somebody may find useful at some time, std.simd would need to be huge, and most of it would never be used. I was referring purely to your 2-vector swizzle idea (or useful high-level ideas in general). Not to hyper-context-specific functions :P My point was that those context specific functions can be implemented using a 2 vector swizzle. LLVM, for example, actually provides access to most vector shuffling instruction through shufflevector, which is basically a 2 vector swizzle. Yeah, I understand. And it's a good suggestion. I'll add support for 2-vector swizzling next time I'm working on it.