Re: Reducing Pegged ASTs
On Tue, Nov 25, 2014 at 4:12 PM, Nordlöw digitalmars-d-learn@puremagic.com wrote: Is there a way to (on the fly) reduce Pegged parse results such as C [0, 6][int, x, ;] +-C.TranslationUnit [0, 6][int, x, ;] +-C.ExternalDeclaration [0, 6][int, x, ;] +-C.Declaration [0, 6][int, x, ;] +-C.DeclarationSpecifiers [0, 4][int] | +-C.TypeSpecifier [0, 4][int] +-C.InitDeclaratorList [4, 5][x] +-C.InitDeclarator [4, 5][x] +-C.Declarator [4, 5][x] +-C.DirectDeclarator [4, 5][x] +-C.Identifier [4, 5][x] to C [0, 6][int, x, ;] +-C.TranslationUnit [0, 6][int, x, ;] +-C.ExternalDeclaration [0, 6][int, x, ;] +-C.Declaration [0, 6][int, x, ;] +-C.TypeSpecifier [0, 4][int] +-C.Identifier [4, 5][x] and still, when needed, be able query that C.Identifier is an instance of C.DirectDeclarator etc? The reducing can be done, either with operators or semantic actions. IIRC there is a free function in Pegged that does it. I did not automate it, because every time I cut down severely a parse tree, I later regret it because I lost information that way. Cutting while still retaining original info (who is this node's ancestor) is more difficult: you would have to store it somewhere anyhow. You cannot create node classes to represent the hierarchy, because of loops in the grammar: an Identifier can have many different ancestors. Note also that Pegged produces parse trees (complete parsing information), not ASTs. ASTs would indeed be much smaller, but we would have to define what are the master nodes in the D grammar. If not this seems like a cool feature to have ;) I guess it would reduce memory requirements by about a magnitude right? If you want to remember the intermediate nodes you cut down, not really, since you still need to store them somehow. I think what's consuming memory right now is that I duplicate the matched strings at each level, even concatenating them at the higher levels. I should let them only in the 'leaves' of the tree (heck, like an AST). Halas, I've no free time to code anything in D these days... but of course, feel free to push any pull request you might have!
Re: accessing numeric template parameters
On Mon, Nov 3, 2014 at 3:27 PM, Dominikus Dittes Scherkl via Digitalmars-d-learn digitalmars-d-learn@puremagic.com wrote: If I have a struct with numeric template parameter, how can I access it within member functions? Like normal member variables? And how about the constructor? struct polynomial(uint base) { private: uint[] N; public: this(uint x) { base = x; } base is part of the type. polynomial is just a 'recipe' for a type, the real struct would be Polynomial!(0), Polynomial!(1), etc. Note that Polynomial!0, Polynomial!1, ... are all different types. Being part of the type means it's defined only at compile-time, you cannot use a runtime value (like 'x') to initialize it. Note that with your current code, `base' is not visible outside Polynomial. You can alias it to a field to make it visible: struct Polynomial(uint base) { alias b = base; // b is visible outside (but set at compile-time !) ... } You can create one like this: Polynomial!2 poly; poly.N = [0,1,0,0,1,1]; assert(poly.b == 2); Of course, you cannot change b: `poly.b = 3;' is forbidden.
Re: how to expand tuple?
Any time you want to return or store a group of values of different types. In a way, tuples are just structs without a name (anonymous structs, if you will). Say you have function `foo' and want it to return an int and a string. In D, you cannot do: (int, string) foo() { ... return (3, abc);} But you can do: import std.typecons: tuple; auto foo() { return tuple(3, abc);} Which is more or less equivalent to: struct FooReturn { int i; string s;} FooReturn foo() { return FooReturn(3, abc);} `Tuple' and its associated factory function `tuple' is just the standard way to group values together in Phobos. You'll see some functions returning Tuples, for example. Some D constructs also recognize std.typecons.Tuple and deal with it elegantly. By defining you own struct (like `FooReturn' in the previous example), you gain some control on your code (you can define how people can interact with FooReturn, you can test for it, etc), but you also lose the possibility of easy interaction with some parts of Phobos.
Re: how to expand tuple?
On Sat, Nov 1, 2014 at 9:34 PM, Suliman via Digitalmars-d-learn digitalmars-d-learn@puremagic.com wrote: Few questions. 1. In examples tuples are created with keyword auto. Can I create them with another keyword. Or auto mean structure of data, that have not standard type like (int or string)? `tuple' is a function defined in the std.typecons module. It's a helper function to create Tuple!(T...), a templated struct acting as a tuple. Don't forget the type will depend on the types of the arguments, so: auto tup = tuple(1.0, abc, [2,3]); contains a float, a string and an array of int's, so it's type is Tuple!(float, string, int[]): Tuple!(float, string, int[]) tup = tuple(1.0, abc, [2,3]); It's a bit long to type, so most people prefer using `auto' for such declarations. 2. How ti expend tuple? I tried to do: auto imglist = tuple(aaa); imglist.expand[sss]; writeln(imglist); but got very strange error: app.d(30): Error: cannot implicitly convert expression (sss) of type string to uint Expand, you mean, as in appending to a tuple? It can be done, but it will create a new type. First, tup.expand gives you access to the 'raw' tuple ( a template parameter list, to be precise) underneath Tuple!(T...). The returned value can be indexed, sliced and its length is known at compile time. Continuing with my example: auto first = tup.expand[0]; // 1.0 auto slice = tup.expand[1..$]; // (abc, [2,3]) auto len = tup.expand.length; // 3, since tup has three elements. That explains the error you get: imglist.expand is a bit like a vector: it can be indexed, but with uint, not with a string. I thought you were expanding it, but to the compiler you were trying to index using a string. If you really want to append to a tuple, you must create a new variable, since the augmented tuple will have a different type: auto tup2 = tuple(tup.expand, 'd'); // tup2 == (1.0, abc, [2,3], 'd') The type of tup2 is then Tuple!(float, string, int[], char) Note that, in your case, as you're using only strings, an array of strings would probably be easier to use.
Re: how to expand tuple?
I thought you were expanding it Drat. *You* thought you were expanding it.
Re: How to pack types with variables in one message to send it to another thread? [tuple]
You can also create new types: struct UseSprite { string s;} struct UseAnimation { string s;} It's not a class instance, it's a class type. Something like `cast(Sprite) null` in parameters. It can be replaced by string Sprite, but in this case I can't use receive() as it is. E.g. send(tid,gameobjectId,Sprite,reload); //must call sprite.reload(); You could use: sent(tid, gameobjectId, UseSprite(reload)); send(tid,gameobjectId,Animation,reload); //must call animation.reload(); sent(tid, gameobjectId, UseAnimation(reload)); Another way, if you have way to determine that gameobjectId points to an animation or a sprite, would be to define a struct name Reload {} and then: sent(tid, gameobjectId, Reload()); Third way: if Animation.reload() and Sprite.reload() are static methods: send(tid, gameobjectId, Sprite.reload); But both messages are (int, string, string) so they can't be separate by different receiving functions. It will be better if messages was (int, Sprite, string) / (int, Animation, string). And it solves my problem. :) But I don't know how to achieve this. See my proposal: define your message as types, directly, and load them for any data necessary for the call. UseAnimation(reload), or whatever.
Re: literate programming in D
Ah that sounds interesting too! Immediately I start thinking in terms like tidlywiki http://tiddlywiki.com/ or something similar, I guess the emacs way described earlier also would support this. I personally always enjoy reading the readthedocs stuff http://docs.readthedocs.org/en/latest/ is that the sort of stuff you mean? Tiddlywiki is interesting, but I'm really talking about the way LP was used by Knuth WEB/CWEB in his explanation of TeX and METAFONT. The Wikipedia article explains it pretty well (http://en.wikipedia.org/wiki/Literate_programming) You write a document combining documentation and code. Then two different programs (weave and ? for WEB) create the resulting documentation for one (HTML, pdf, whatever) and the code (a .d file) for another. I discovered LP through the incredible book Physically-based Ray-Tracing. The book is one program, explained and documented using literate progamming. It's an incredible achievement (1000+ pages of explanations!). See: www.pbrt.org and more precisely: http://www.pbrt.org/chapters/pbrt_chapter7.pdf The code begins at page 18 of the pdf. For example, at page 22: Sample Method Definitions ≡ Sample::Sample(SurfaceIntegrator *surf, VolumeIntegrator *vol, const Scene *scene) { surf-RequestSamples(this, scene); vol-RequestSamples(this, scene); Allocate storage for sample pointers 301 Compute total number of sample values needed 302 Allocate storage for sample values 302 } The snippet Sample Method Definitions introduces three new snippets, that will be explained elsewhere. Other snippets might also use the same references, if needed. It's not complicated to write a D tool for that, I did that some time ago. Once you define your begin/end token for snippet definitions, you can parse them to extract the way they are linked.
Re: How to build dlang.org dd files
dmd -c -o- macros.ddoc doc.ddoc -Df{ddoc_filename}.html {ddoc_filename}.dd If someone knows of a more official syntax, please let me know. I don't know of another syntax, but could you please put this somewhere on the wiki? Maybe in the cookbook section: http://wiki.dlang.org/Cookbook
Re: alias and mixin
It is basically just an annoying grammar limitation that does not allow to use mixin / __traits as an identifier. The usual helper template: ``` alias helper(alias a) = a; ``` helps for aliasing __traits and anonymous function templates (x = x+1), but I don't see an easy solution for mixin inside the current language, apart from pushing the mixin outside.
Re: alias and mixin
I recommend slightly more generic form: template Alias(T...) if (T.length == 1) { alias Alias = T[0]; } it is quite helpful in templated code to be able to alias _anything_ That's what I use also, but didn't want another thread on the (T...) if (T.length ==1) trick :) But yeah, no fun for mixins :( Mainly, I slap them in my code, then slowly migrate them outwards (in 'head' position) until that compiles...
Re: literate programming in D
On Sat, Aug 30, 2014 at 1:37 AM, nikki wrote: I wasn't too happy about it and I wrote my own little parse thingie and have a literate version nice and meta and small and sloppy ;) http://nikkikoole.github.io/docs/dokidokDOC.html I use it to change my d sourcefile slightly (into valid markdown) then I use a node module (ghmd) to make sortof sexy html from that. Nice. Maybe you could strip the initial whitespaces in the code parts: due to blocks, your code lines are shifting to the right. If you document something that's inside a method inside a class, you're bound to have problems :) Right now, you're documenting your code in a linear way. That's good, but for me, most of LP is based around the idea of naming snippets and referring to them in code, to be explained elsewhere: ``` Here is the main loop: Main= void main() { Initialize Variables Precompute State foreach(i; 0..max) { Do Computation } } Before doing all this, we need to initialize the variables: Initialize Variables= ... ``` Of course, snippets can refer to other snippets, recursively. Do you have any plan to go there?
Re: literate programming in D
On Friday, 29 August 2014 at 23:58:19 UTC, Chris Cain wrote: I used https://www.npmjs.org/package/literate-programming (+ pandoc) to do this when writing https://dl.dropboxusercontent.com/u/2206555/uniformUpgrade.pdf in markdown. Do you remember if some snippets can be hidden in the final documented output (I don't find that in this package)? I know the goal of LP is to explain your code, but I remember using that with other systems: that's useful when you don't want to show some plumbing (for a tutorial for example, where you want to concentrate on the main suject).
Re: getting the adress of a function by its name in string format
instead I would like to use EAT_FOOD_DECISION and EAT_FOOD_BEHAVIOUR and get the functions? Is that possible somehow? If all your functions had the same signature, you could use an associative array FunctionType[string] and initialize it: FunctionType[string] myFuncs; myFuncs[EAT_FOOD_DECISION] = EAT_FOOD_DECISION; But it seems they have different types?
Re: Variadic parameter of length 1
On Wed, Aug 20, 2014 at 5:34 PM, Dominikus Dittes Scherkl via Digitalmars-d-learn digitalmars-d-learn@puremagic.com wrote: On Wednesday, 20 August 2014 at 15:26:14 UTC, monarch_dodra wrote: AFAIK, it's a historical workaround to accept T as either alias or not alias, as varargs have auto alias. EG: foo!int //OK foo!hello //OK too Ah, ok. And why historical? Is that not necessary anymore? What better solution is there today? No better solution that I know of. alias template parameters (alias a) match symbols (names, user-defined types) whereas type parameter (T) match only pure types. So when we need to match anything, we use (T...) if (T.length == 1)
Re: No Output with shebang.
gdc just compiles the program to a.out. It doesn't run the resulting executable. You need to use something like rdmd instead of gdc. rdmd compiles to some temporary location and then runs the executable. Wow, that was fast. Thanks a lot! Can compiler switches be used with the shebang notation? If yes, there is certainly a GDC flag (-run?) that tells it to run the generated executable.
Re: iterate traits ?
A foreach becomes compile-time whenever the aggregate is a purely compile- time construct such as a tuple. Yeah, I think you transformed it into a runtime array by using [ ... ]. Tuples with compatible types can be 'downgraded' to arrays that way. But there is no need to: tuples are iterable, indexable and slice-able in D. import std.stdio; struct Vertex {float[3] position; float[3] normal;} void main() { foreach(e; __traits(allMembers, Vertex)) { alias tt = typeof(__traits(getMember, Vertex, e)); // worksforme writeln(tt.sizeof); } }
Re: @safe, pure and nothrow at the beginning of a module
If I understand correctly Adam Ruppe's Cookbook, by putting @safe: pure: nothrow: at the beginning of a module, I distribute it on all definitions, right? Even methods, inner classes, and so on? I read Adam's book again and I was wrong: Chapter 7, p. 173: You may add @safe: to the top of your module and aggregate definitions to apply the annotation to all function that follows, instead of writing it on each individual function. So, first, he's talking only about @safe (though I suppose it works the same for all annotations) and he says: *and aggregate definitions*. We indeed need to put annotations inside aggregates to affect their innards. If that's true, I have a lot of annotation sprinkling to do.
Re: @safe, pure and nothrow at the beginning of a module
On Sat, Aug 16, 2014 at 1:30 PM, Artur Skawina via Digitalmars-d-learn digitalmars-d-learn@puremagic.com wrote: On 08/16/14 13:18, Philippe Sigaud via Digitalmars-d-learn wrote: We indeed need to put annotations inside aggregates to affect their innards. If that's true, I have a lot of annotation sprinkling to do. It's not true for @safe, but true for some other attributes. http://forum.dlang.org/post/mailman.125.1397731134.2763.digitalmar...@puremagic.com Okay... So @safe includes child scopes. I suppose @trusted and @system work in the same way. *but* nothrow, @nogc and UDA's do not include child scopes. Putting them at the beginning of a module will not affect methods in aggregates... What's the situation for pure? (I don't have a D compiler handy right now, or I would test it myself).
Re: @safe, pure and nothrow at the beginning of a module
Artur: @safe, @trusted, @system, shared, immutable, const, inout and `extern (...)` affect child scopes. `synchronized` does too, but in a rather unintuitive way; hopefully nobody uses this. ;) Well, I also hope no one uses inout: at the module level? Other attributes, including 'pure' and 'nothrow' only affect symbols in the current scope. There we are. Good to know, thanks.
Re: Appender is ... slow
Quick test... Ah, thanks a lot Jonathan. I kept telling me I should probably test it on a simple case. OK, the good news is, Appender works in these cases (I mean, that's good news for Phobos). Now, I just have to find out why it's slower in my case :) import std.array; import std.datetime; import std.stdio; enum size = 1000; void test1() { auto arr = appender!(int[])(); foreach(n; 0 .. size) arr.put(n); } I used ~= to append to an Appender. The examples use .put, but ~= is documented so I considered the operator was just syntax sugar. I didn't have a look at its implementation. void test2() { int[] arr; foreach(n; 0 .. size) arr ~= n; } void test3() { auto arr = new int[](size); foreach(n; 0 .. size) arr[n] = n; } This one is simple and interesting. In my case I don't know the length in advance (I'm doing some parsing and predicting the size of the parse forest based on the input length is somewhat tricky), but I can pre-allocate some, based on a simple heuristics. void test4() { auto arr = uninitializedArray!(int[])(size); foreach(n; 0 .. size) arr[n] = n; } Oh, I didn't know this one. With size being 1000, I get 178 ms, 229 μs, and 4 hnsecs 321 ms, 272 μs, and 8 hnsecs 27 ms, 138 μs, and 7 hnsecs 24 ms, 970 μs, and 9 hnsecs Same here, good. Using ~= n instead of .put(n) gives me results consistently slightly slower for Appender (170 ms - 190 ms, repeatedly, even going back and forth between the two possibilities. I created a test1prime to test that. With size being 100,000, I get 15 secs, 731 ms, 499 μs, and 1 hnsec 29 secs, 339 ms, 553 μs, and 8 hnsecs 2 secs, 602 ms, 385 μs, and 2 hnsecs 2 secs, 409 ms, 448 μs, and 9 hnsecs Ditto. OK, that's good. Also, it's still slower with using Appender ~= n instead of Appender.put. (18s instead of 15, 20% slower) So, kids: don't do that. So, it looks like using Appender to create an array of ints is about twice as fast as appending to the array directly, and unsurprisingly, creating the array at the correct size up front and filling in the values is far faster than either, whether the array's elements are default-initialized or not. And the numbers are about the same if it's an array of char rather than an array of int. Perfect. That also means my go-to method will still be using standard arrays, but with pre-allocation. I just feel stupid writing that, because it's obvious that reserving things should give it better speed. Also, curiously, if I add a test which is the same as test2 (so it's just appending to the array) except that it calls reserve on the array with size, the result is almost the same as not reserving. It's a smidgeon faster but probably not enough to matter. So, it looks like reserve doesn't buy you much for some reason. Maybe the extra work for checking whether it needs to reallocate or whatever fancy logic it has to do in ~= dwarfs the extra cost of the reallocations? That certainly seems odd to me, but bizarrely, the evidence does seem to say that reserving doesn't help much. That should probably be looked into. Yeah, I get a small boost of 5% compared to not reserving at size 1000, which completely disappears for longer arrays. (No different for size 100_000). In any case, from what I can see, if all you're doing is creating an array and then throwing away the Appender, it's faster to use Appender than to directly append to the array. Indeed. Maybe that changes with structs? I don't know. I'm using classes, because what I'm pushing into the Appender are graph nodes and I got fed up with tracing pointer to strucs everywhere. Maybe I should change back to structs and see what it does. It would be interesting to know what's different about your code that's causing Appender to be slower, but from what I can see, it's definitely faster to use Appender unless you know the target size of the array up front. Good conclusion. Thanks for your help. My takeaway idea is that I'll use arrays, but 'new T[](size)' them before. If that makes heavy concatenation 10 times faster, it should have a positive effect (I'm not of course waiting for anything near a 10x boost in my computation time).
Re: Appender is ... slow
I wonder if using plain `Array` instead may be result in better performance where immutability is not needed. Hmm, no: module appendertest; import std.array; import std.datetime; import std.stdio; import std.container; enum size = 1_000; void test1() { auto arr = appender!(int[])(); foreach(n; 0 .. size) arr.put(n); } void test1prime() { auto arr = appender!(int[])(); foreach(n; 0 .. size) arr ~= n; } void test2() { int[] arr; foreach(n; 0 .. size) arr ~= n; } void test2prime() { int[] arr; arr.reserve(size); foreach(n; 0 .. size) arr ~= n; } void test3() { Array!int arr; foreach(n; 0 .. size) arr ~= n; } void test3prime() { Array!int arr; arr.reserve(size); foreach(n; 0 .. size) arr ~= n; } void test4() { auto arr = new int[](size); foreach(n; 0 .. size) arr[n] = n; } void test5() { auto arr = uninitializedArray!(int[])(size); foreach(n; 0 .. size) arr[n] = n; } void main() { auto result = benchmark!(test1, test1prime, test2, test2prime, test3, test3prime, test4, test5 )(10_000); writeln(Appender.put :, cast(Duration)result[0]); writeln(Appender ~=:, cast(Duration)result[1]); writeln(Std array :, cast(Duration)result[2]); writeln(Std array.reserve :, cast(Duration)result[3]); writeln(Array :, cast(Duration)result[4]); writeln(Array.reserve :, cast(Duration)result[5]); writeln(new T[]() :, cast(Duration)result[6]); writeln(uninitializedArray :, cast(Duration)result[7]); } Times: Appender.put :157 ms, 602 μs, and 3 hnsecs Appender ~=:182 ms, 807 μs, and 1 hnsec Std array :256 ms, 210 μs, and 7 hnsecs Std array.reserve :244 ms, 770 μs, and 4 hnsecs Array :336 ms, 207 μs, and 3 hnsecs Array.reserve :321 ms, 500 μs, and 6 hnsecs new T[]() :28 ms, 496 μs, and 6 hnsecs uninitializedArray :26 ms and 620 μs
Re: Appender is ... slow
On Thu, Aug 14, 2014 at 11:33 PM, Joseph Rushton Wakeling via Digitalmars-d-learn digitalmars-d-learn@puremagic.com wrote: On 14/08/14 19:16, Philippe Sigaud via Digitalmars-d-learn wrote: Do people here get good results from Appender? And if yes, how are you using it? An example where it worked for me: http://braingam.es/2013/09/betweenness-centrality-in-dgraph/ (You will have to scroll down a bit to get to the point where appenders get introduced.) I remember reading this and loving it! Any news on this? Do you have new algorithms?
Re: Appender is ... slow
It is very different with better compiler though : $ ldmd2 -release -O a.d $ ./appendertest Appender.put :378 ms, 794 μs, and 9 hnsecs Appender ~=:378 ms, 416 μs, and 3 hnsecs Std array :2 secs, 222 ms, 256 μs, and 2 hnsecs Std array.reserve :2 secs, 199 ms, 64 μs, and 5 hnsecs Array :349 ms and 250 μs Array.reserve :347 ms, 694 μs, and 1 hnsec new T[]() :37 ms, 989 μs, and 8 hnsecs uninitializedArray :39 ms, 333 μs, and 3 hnsecs (size 10_000) OK, same here, except std array gives me only 1.4 s, while the other timings are about the same. (0.14 alpha2 : ldmd2 -O -inline). Drat, that means testing on many different compilers. Oh well, let's start small: pre-allocating, better algorithms, then I'll do real speed instrumentation.
Re: Appender is ... slow
On Fri, Aug 15, 2014 at 1:57 PM, Messenger via Digitalmars-d-learn digitalmars-d-learn@puremagic.com wrote: T[size] beats all of those on dmd head, though it is inarguably a bit limiting. I confirm (even with 2.065). With ldc2 it's optimized out of the way, so it gives 0 hnsecs :-) Hmm, what about a sort of linked list of static arrays, that allocates a new one when necessary?
Re: Appender is ... slow
Well, I created a wrapper around a std.array.uninitializedArray call, to manage the interface I need (queue behavior: pushing at the end, popping at the beginning). When hitting the end of the current array, it either reuse the current buffer or create a new one, depending of the remaining capacity. On the 'synthetic' benchmarks, it performs quite reasonably: half the time of Array or Appender (twice faster), 5x faster than standard array, and 3-4x slower than uninitializedArray. And... It does not change the timings in my code, it even makes things slower when pre-allocating to much. Only by pre-allocating only a few elements do I get back the original timings. So, I guess I'm suffering from a bad case of premature optimization :) I thought that, having lots of concatenation in my code, that'd be a bottleneck. But it appears than pre-allocation does not give me any speed-up. Well, at least it got me thinking, testing LDC a bit more and learning things on Array and Appender ;) Thank for your help guys, it's now time for the -profile switch again...
@safe, pure and nothrow at the beginning of a module
So I'm trying to use @safe, pure and nothrow. If I understand correctly Adam Ruppe's Cookbook, by putting @safe: pure: nothrow: at the beginning of a module, I distribute it on all definitions, right? Even methods, inner classes, and so on? Because I did just that on half a dozen of modules and the compiler did not complain. Does that mean my code is clean(?) or that what I did has no effect?
Re: Appender is ... slow
On Friday, 15 August 2014 at 16:48:10 UTC, monarch_dodra wrote: On Friday, 15 August 2014 at 14:40:36 UTC, Philippe Sigaud wrote: Well, I created a wrapper around a std.array.uninitializedArray call, to manage the interface I need Make sure you don't use that if your type has elaborate construction, or assumes a certain initial state (unless you are actually emplacing your objects of course). Hmm, what's elaborate construction? They are classes and have constructors, of course. I assumed that this produced only null's in the array. I thought that, having lots of concatenation in my code, that'd be a bottleneck. But it appears than pre-allocation does not give me any speed-up. If you are using raw GC arrays, then the raw append operation will, outweigh the relocation cost on extension. So pre-allocation wouldn't really help in this situation (though the use of Appender *should*) OK.
Re: @safe, pure and nothrow at the beginning of a module
In another module I marked as '@safe:' at the top, the compiler told me that a class opEquals could not be @safe (because Object.opEquals is @system). So it seems that indeed a module-level '@safe:' affects everything, since a class method was found lacking. (I put a @trusted attribute on it).
Re: Appender is ... slow
On Fri, Aug 15, 2014 at 10:04 PM, John Colvin via Digitalmars-d-learn digitalmars-d-learn@puremagic.com wrote: compiler, version, OS, architecture, flags? Compiler: DMD 2.065 and LDC 0.14 OS: Linux 64bits (8 cores, but there is no parallelism here) flags: -O -release -inline (and -noboundscheck for DMD) Have you looked at the assembly to check that all the Appender method calls are being inlined? I do not know how to look at the assembly, neither do I know how to see if Appender method calls are being inlined. I did spend some time with -profile and gained a nice 10% increase in speed with that, fighting bottlenecks in my code.
Re: Appender is ... slow
I don't know much about Phobos appender implementation details but the key thing with reusable buffer is avoid freeing them. AFAIR Appender.clear frees the allocated memory but `Appender.length = 0` does not, making it possible to just overwrite stuff again and again. I call .clear() only at the beginning of the computation, to avoid any strange effects with std.datetime.benchmark (using benchmark with memoizing functions can lead to strange results if one does not take care to flush any result between to calls.) After that initial call to clear, I just append. The thing is, it's not the first time it happens. For years, I tried to use Appender to get faster code, to no avail. btw, I saw your Dconf talk yesterday, nice content! And thanks for talking about Pegged! It might interest you to know that the code I'm trying to use Appender on is a new engine for Pegged, based on GLL parsing, that should be able to produce a parser for any grammar, even ambiguous ones.
Re: Appender is ... slow
I've never really tried to benchmark it, but it was my understanding that the idea behind Appender was to use it to create the array when you do that via a lot of appending, and then you use it as a normal array and stop using Appender. That's how I use it, yes. It sounds like you're trying to use it as a way to manage reusing the array, and I have no idea how it works for that. There is a misunderstanding there: I'm using clear only to flush the state at the beginning of the computation. The Appender is a class field, used by the class methods to calculate. If I do not clear it at the beginning of the methods, I keep appending new results to old computations, which is not what I want. But really, calling clear is a minor point: I'm interested in Appender's effect on *one* (long, concatenation-intensive) computation. I've never actually benchmarked it for just creating arrays via appending. I'd just assumed that it was faster than just using ~=, because that's what it's supposedly for. But maybe I just completely misunderstood what the point of Appender was. I don't know. People here keep telling newcomers to use it, but I'm not convinced by its results. Maybe I'm seeing worse results because my arrays are do not have millions of elements and Appender shines for long arrays?
Re: Appender is ... slow
There is a misunderstanding there: I'm using clear only to flush the state at the beginning of the computation. The Appender is a class field, used by the class methods to calculate. If I do not clear it at the beginning of the methods, I keep appending new results to old computations, which is not what I want. But really, calling clear is a minor point: I'm interested in Appender's effect on *one* (long, This is exactly what I propose to change - set `length` to 0 instead of calling `clear`. That way you will keep using same memory chunk simply abandoning its old state at the beginning of each computation. You mean by using the shrinkTo method? (Appender does not have a length, that's a bit of a bother btw). I just did, it does not change anything. Too bad. Heck, my code is simpler to read and use *and* faster by using a bog-standard D array. I'll keep my array for now :)
Re: Appender is ... slow
Thanks! Repeating what I have mentioned during DConf talk - have you ever considered proposing Pegged for Phobos inclusion? It feels like important bit of infrastructure to me. At the time, it was considered (rightfully) far too slow and memory-hogging. I think having a generic lexer and a standard D parser in Phobos would already be a great step forward.
Re: Are Delimited strings and HereDoc strings just here to suck ?
On Mon, Aug 11, 2014 at 10:09 PM, H. S. Teoh via Digitalmars-d-learn digitalmars-d-learn@puremagic.com wrote: On Mon, Aug 11, 2014 at 07:47:44PM +, Klaus via Digitalmars-d-learn wrote: I mean when writing a D lexer, you necessarly reach the moment when you think: Oh no! is this feature just here to suck ? The crazy variety of ways to write string literals in D, OTOH, *is* a bit over the top, as I found out myself when I also tried writing a D lexer. :-P Out of curiosity, how does a lexer deal with heredocs? It's a sort of... user-defined token, right?
Re: Are Delimited strings and HereDoc strings just here to suck ?
On Mon, Aug 11, 2014 at 10:58 PM, H. S. Teoh via Digitalmars-d-learn digitalmars-d-learn@puremagic.com wrote: In Flex, one way you can implement heredocs is to have a separate mode where the lexer is scanning for the ending string. So basically you have a sub-lexer that treats the heredoc as three tokens, one that defines the ending string for the heredoc (which is never returned to the caller), one that contains the content of the heredoc, and the terminating token (also never returned to the caller). Ah, a small, specialized sub-lexer. OK, I get it.
Re: How to easily construct objects with multi-param constructors from lazy ranges?
Yea, but that won't work for forward ranges. It only provides opIndex if the underlying range provides it. Since the chunk size is a runtime parameter it can't implement opIndex efficiently for non-random access ranges. But in your case, your range is random-access, no? Or else, you can always map array on the chunks... staticChunks was a bit of a misnomer. staticTake would be a better name. The range would contains a static array and pops that number of elements from the input range. Then, opIndex can easily be defined. What about takeExactly?
Re: Help with porting grammar from PEGjs to D for dustjs project!
On Wed, Aug 6, 2014 at 9:09 AM, Uranuz via Digitalmars-d-learn digitalmars-d-learn@puremagic.com wrote: What I was thinking about is possibility to change ParseTree struct with user-defined version of it. And I was thinking about setting tree type as template parameter to grammar: grammar!(MyParseTree)( Arithmetic: ... ); That's already the case, look at https://github.com/PhilippeSigaud/Pegged/blob/master/pegged/parser.d on line 134, for example. struct GenericPegged(TParseTree) { ... } And then, the library alias a standard version (line 1531): alias GenericPegged!(ParseTree).Pegged Pegged; Which means the customer-facing Pegged parser is in fact a generic parser specialized on ParseTree. But you can substitute your own parse tree. That's of course the same for all parsers: GenericXXX(TParseTree) {...} and then alias XXX = GenericXXX!(ParseTree); But you're right, it's not really documented and I don't have a template checking whether TParseTree respect some static inferface. This parameterization was asked by someone on github, but I don't think they used it finally. ParseTree is described here: https://github.com/PhilippeSigaud/Pegged/wiki/Parse-Trees Maybe we can continue this thread by private mail? I'm not sure people on the D list are that interested by the internals of a library.
Re: Inner struct accessing host member
hmmm static and private... other keywords to try, but offhand it's been a while i don't know if either would change the behavior. Could just be inner scope limitations. Might be other tags/modifiers... I feel helpless :( No need to ;-) Thanks for your help, don't sweat it too much. I'm not sure if it would help, but sometimes if you reverse the logic you might get what you want by putting the data in B instead of A. I have a lot of Bs (nodes in a graph). They compute some things and when they get a result, they update A's field. Each A holds the entry point to their inner graph of Bs and waits for the results. So I don't see how I could invert it, really. What *could* do it to have the graph of Bs in thread and sending results as messages to another thread, where A is waiting for them. It's just... I'm so used to being able to mix and compose 'concepts' in D: structs in functions, classes in classes in structs, functions returning functions returning structs, etc. I'm used to begin able to organise my code as I see the problem space. But here, with a struct-in-a-struct, I hit a wall. Not fun, but not problematic too...
Re: Help with porting grammar from PEGjs to D for dustjs project!
Is there multiline comments available inside PEGGED template? As far as I understand inline comments are set via # sign. No, no multiline comment. That's based on the original PEG grammar, which allows only #-comments.
Re: How to easily construct objects with multi-param constructors from lazy ranges?
Some range which takes an at compile time known number of elements from an input range and provides opIndex seems perfect to me, but as far as I know there's no such thing in Phobos. There is chunks: http://dlang.org/phobos/std_range.html#chunks
Re: static array in templated struct/class
http://pastebin.com/34sbffSa Your problem comes from lengthSquared: public auto lengthSquared = function () = val.reduce!((a,b) = a + b*b); That's an unusual way to define a method. Any reason why you are using a pointer to a function as a member? Do you need to be able to redefine it at runtime? I guess that in this case, the compiler cannot determine its return type and/or its size? I'd use: public auto lengthSquared () { return val.reduce!((a,b) = a + b*b);}
Inner struct accessing host member
I'd have thought that this would work: struct A { int[] i; B b; struct B { void foo() { i ~= 1;} } } void main() { A a; a.b.foo(); } But the compiler tells me 'need this for i of type int[]'. Is there any way I can gain access on i inside B?
Re: Inner struct accessing host member
On Tue, Aug 5, 2014 at 11:37 PM, Martijn Pot via Digitalmars-d-learn digitalmars-d-learn@puremagic.com wrote: Does this help : http://www.digitalmars.com/d/archives/digitalmars/D/learn/Nested_struct_member_has_no_access_to_the_enclosing_class_data_38294.html Yes, that helps: that explains why it does not wor :). I changed my code to use classes. It's a bit less handy, but it works.
Re: Inner struct accessing host member
why it does not wor :). why it does not *work*, of course. Sigh.
Re: Inner struct accessing host member
On Tuesday, 5 August 2014 at 22:14:23 UTC, abanstadya wrote: programming Q, either youra newb or not, should rather be posted to 'http://forum.dlang.org/group/digitalmars.D.learn'. Your post appears on 'http://forum.dlang.org/group/digitalmars.D' which is more related to the lang. design rather to programming Q. Take care next time bro. This *is* D.learn, bro.
Re: Inner struct accessing host member
On Tuesday, 5 August 2014 at 23:47:00 UTC, Artur Skawina via Digitalmars-d-learn wrote: Is there any way I can gain access on i inside B? Not directly, but as you ask for /any/ way -- yes: struct B { void foo() { outer.i ~= 1; } ref A outer() inout @property { return *cast(A*)(cast(void*)this-A.b.offsetof); } } Note this will work only as long as you have just one B instance in A and B is never created or copied outside of A. OK. I have en entire graph, whose nodes are Bs inside A. So that might not be totally appropriate for me. Thanks anyway, I always forget about offsetof
Re: Inner struct accessing host member
Era: broken_b.foo(); //i_a is accessible invisibly because overridden or transformed assuming it would be converted or copied/moved as appropriate. return b; //if a is a local variable then b becomes invalid even though it's a struct. return i_b; //same as return b return broken_b; //same as above two cases. I see. I didn't know one could create an A.B 'outside'. I saw inner types as Voldemort types, but that is true only for inner structs in functions. Now a current way to make it safe while still leaving it structs could be passing a reference to either the outer struct or the variable in question. For simplicity it would probably be the struct. (...) Or less safe is to use a pointer and assign it when b instantiates to point back to A.. But if you pass B around without A and A goes out of scope... same problem... Maybe i'm over-thinking it. I already tried to propagate a ref through A's methods, but that made a mess: I have lots of methods, which have all to transmit this ref, only for *one* of them being able to update it. Thanks for you explanations :) I'm now using classes and inner classes. I'm not fond of classes, but that's working correctly.
Re: Threadpools, difference between DMD and LDC
Without going into much detail: Threads are heavy, and creating a thread is an expensive operation (which is partially why virtually every standard library includes a ThreadPool). I haven't looked into detail your code, but consider using the TaskPool if you just want to schedule some tasks to run amongst a few threads, or potentially using Fibers (which are fairly light-weight) instead of Threads. OK, I get it. Just to be sure, there is no ThreadPool in Phobos or in core, right? IIRC, there are fibers somewhere in core, I'll have a look. I also heard the vibe.d has them.
Re: Threadpools, difference between DMD and LDC
On Mon, Aug 4, 2014 at 2:13 PM, Chris Cain via Digitalmars-d-learn digitalmars-d-learn@puremagic.com wrote: OK, I get it. Just to be sure, there is no ThreadPool in Phobos or in core, right? There is. It's called taskPool, though: http://dlang.org/phobos/std_parallelism.html#.taskPool Ah, std.parallelism. I stoopidly searched in std.concurrency and core.* Thanks!
Re: Threadpools, difference between DMD and LDC
On Mon, Aug 4, 2014 at 3:36 PM, Dicebot via Digitalmars-d-learn digitalmars-d-learn@puremagic.com wrote: Most likely those threads either do nothing or are short living so you don't get actually 10 000 threads running simultaneously. In general you should expect your operating system to start stalling at few thousands of concurrent threads competing for context switches and system resources. Creating new thread is rather costly operation though you may not spot it in synthetic snippets, only under actual load. Modern default approach is to have amount of worker threads identical or close to amount of CPU cores and handle internal scheduling manually via fibers or some similar solution. That's what I guessed. It's juste that I have task that will generate other (linked) tasks, in a DAG. I can use a thread pool of 2-8 threads, but that means storing tasks and their relationships (which is waiting on which, etc). I rather liked the idea of spawning new threads when I needed them ;) If you are totally new to the topic of concurrent services, getting familiar with http://en.wikipedia.org/wiki/C10k_problem may be useful :) I'll have a look. I'm quite new, my only knowledge comes from reading the concurrency threads here, std.concurrency, std.parallelism and TDPL :)
Re: Threadpools, difference between DMD and LDC
On Mon, Aug 4, 2014 at 6:21 PM, Dicebot via Digitalmars-d-learn digitalmars-d-learn@puremagic.com wrote: vibe.d additions may help here: http://vibed.org/api/vibe.core.core/runTask http://vibed.org/api/vibe.core.core/runWorkerTask http://vibed.org/api/vibe.core.core/workerThreadCount task abstraction allows exactly that - spawning new execution context and have it scheduled automatically via underlying fiber/thread pool. However, I am not aware of any good tutorials about using those so jump in at your own risk. Has anyone used (the fiber/taks of) vibe.d for something other than powering websites?
Re: Threadpools, difference between DMD and LDC
On Mon, Aug 4, 2014 at 6:38 PM, Russel Winder via Digitalmars-d-learn digitalmars-d-learn@puremagic.com wrote: Are these std.concurrent threads or std.parallelism tasks? A std.parallelism task is not a thread. Like Erlang or Java Fork/Join framework, the program specifies units of work and then there is a thread pool underneath that works on tasks as required. So you can have zillions of tasks but there will only be a few actual threads working on them. That's it. Many tasks, a few working threads. That's what I'm converging to. They are not particularly 'concurrent', but they can depend on one another. My only gripes with std.parallelism is that I cannot understand whether it's interesting to use the module if tasks can create other tasks and depend on them in a deeply interconnected graph. I mean, if I have to write lots of scaffolding just to manage dependencies between task, I might as well built it on core.thread and message passing directly. I'm becoming quite enamored of message passing, maybe because it's a new shiny toy for me :) That's for parsing, btw. I'm trying to write a n-core engine for my Pegged parser generator project. Most likely those threads either do nothing or are short living so you don't get actually 10 000 threads running simultaneously. I suspect it is actually impossible to start this number of kernel threads on any current kernel So, what happens when I do void doWork() { ... } Tid[] children; foreach(_; 0 .. 10_000) children ~= spawn(doWork); ? I mean, it compiles and runs happily. In my current tests, I end the application by sending all thread a CloseDown message and waiting for an answer from each of them. That takes about 1s on my machine. I have no current data, but it used to be that for a single system it was best to have one or two more threads than the number of cores. Processor architectures and caching changes so new data is required. I am sure someone somewhere has it though. I can add that, depending on the tasks I'm using, it's sometime better to use 4, 6, 8 or 10 threads, repeatedly for a given task. I'm using a Core i7, Linux sees it as an 8-core. So, well, I'll try and see.
Re: Threadpools, difference between DMD and LDC
https://github.com/D-Programming-Language/phobos/pull/1910 Very interesting discussion, thanks. I'm impressed by the amount of work you guys do on github.
Threadpools, difference between DMD and LDC
I'm trying to grok message passing. That's my very first foray into this, so I'm probably making every mistake in the book :-) I wrote a small threadpool test, it's there: http://dpaste.dzfl.pl/3d3a65a00425 I'm playing with the number of threads and the number of tasks, and getting a feel about how message passing works. I must say I quite like it: it's a bit like suddenly being able to safely return different types from a function. What I don't get is the difference between DMD (I'm using 2.065) and LDC (0.14-alpha1). For DMD, I compile with -O -inline -noboundscheck For LDC, I use -03 -inline LDC gives me smaller executables than DMD (also, 3 to 5 times smaller than 0.13, good job!) but above all else incredibly, astoundingly faster. I'm used to LDC producing 20-30% faster programs, but here it's 1000 times faster! 8 threads, 1000 tasks: DMD: 4000 ms, LDC: 3 ms (!) So my current hypothesis is a) I'm doing something wrong or b) the tasks are optimized away or something. Can someone confirm the results and tell me what I'm doing wrong?
Threadpools, difference between DMD and LDC
I'm trying to grok message passing. That's my very first foray into this, so I'm probably making every mistake in the book :-) I wrote a small threadpool test, it's there: http://dpaste.dzfl.pl/3d3a65a00425 I'm playing with the number of threads and the number of tasks, and getting a feel about how message passing works. I must say I quite like it: it's a bit like suddenly being able to safely return different types from a function. What I don't get is the difference between DMD (I'm using 2.065) and LDC (0.14-alpha1). For DMD, I compile with -O -inline -noboundscheck For LDC, I use -03 -inline LDC gives me smaller executables than DMD (also, 3 to 5 times smaller than 0.13, good job!) but above all else incredibly, astoundingly faster. I'm used to LDC producing 20-30% faster programs, but here it's 1000 times faster! 8 threads, 1000 tasks: DMD: 4000 ms, LDC: 3 ms (!) So my current hypothesis is a) I'm doing something wrong or b) the tasks are optimized away or something. Can someone confirm the results and tell me what I'm doing wrong?
Re: Help with porting grammar from PEGjs to D for dustjs project!
Uranuz: http://akdubya.github.io/dustjs/ So I need some help with rewriting grammar from PEGjs into PEGGED. Is this the grammar? https://github.com/akdubya/dustjs/blob/master/src/dust.pegjs If so, then I think I can provide some help. But I don't get what output you want (see below). Also I don't understand in PEGGED (I have not tried to use it yet) how to generate some logic from AST. Where should I describe it or should I walk around all nodes for somehow and generate code for them. You can put semantic actions in the grammar (code between curly brackets). dust.pegjs seems to have that in their grammar definition also (all these { return something } blocks) Or you can walk the parse tree afterwards. See the Pegged tutorial here: https://github.com/PhilippeSigaud/Pegged/wiki/Pegged-Tutorial More particularly: https://github.com/PhilippeSigaud/Pegged/wiki/Using-the-Parse-Tree The example explains (I hope) how to use a wiki grammar to parse wiki text and output LaTeX code. Goal of this is to use dust template system as template engine at server side. More concretely, what's the goal? A template as input and... what should be output? If I understand correctly, dustjs produces Javascript code. Is that what you want? Or do you want D code? Also, did you have a look at vide.d and its Diet templates?
Re: Threadpools, difference between DMD and LDC
This is correct – the LLVM optimizer indeed gets rid of the loop completely. OK,that's clever. But I get this even when put a writeln(some msg) inside the task. I thought a write couldn't be optimized away that way and that it's a slow operation? Anyway, I discovered Thread.wait() in core in the meantime, I'll use that. I just wanted to have tasks taking a different amount of time each time. I have another question: it seems I can spawn hundreds of threads (Heck, even 10_000 is accepted), even when I have 4-8 cores. Is there: is there a limit to the number of threads? I tried a threadpool because in my application I feared having to spawn ~100-200 threads but if that's not the case, I can drastically simplify my code. Is spawning a thread a slow operation in general?
Re: Help with porting grammar from PEGjs to D for dustjs project!
On Mon, Aug 4, 2014 at 7:13 AM, Uranuz via Digitalmars-d-learn digitalmars-d-learn@puremagic.com wrote: I am real noob about grammar description languages so I need some explanation about it. As far as I understand expressions in curly bracers are used to modify syntax tree just in process of parsing instead of modifying it after? Yes, that's it. Or at least that's the way Pegged does it. I'm not such a specialist myself, I just dabbled in it to write Pegged. As I understand it, many parsers do not produce a parse tree, they only 'return' what their embedded action tell them to. Personally, I have a slight preference to using the parse tree once it's complete. a) Because that way I have access to all the information (parent nodes, sibling nodes, even far way) whereas when doing it with an action means you only have the local, current node context and b) because it decouples steps that are in my mind separated anyway: parsing, then producing a value out of the parse tree. A bit like ranges in D, and Walter and his components programming speech. How I could use PEGGED to map some code to these parsed expressions to generate code that will perform operations defined by this grammar? Should I walk around all the syntax tree and just append code to some string and mix it in then or are there some features for code generation? You can insert semantic actions inside the grammar definition, as is done by Dustjs, or you can have a function walking the tree afterwards. For D, since Pegged works at compile time, you can have your parse tree at compile time. Use the walking function to generate D code (a string) and mix it in. enum parseTree = Grammar(input); // CT parsing string codeMaker(ParseTree pt) { ... } // recursive walker mixin(codeMaker(parseTree)); See https://github.com/PhilippeSigaud/Pegged/wiki/Using-the-Parse-Tree If what you need is generating Javascript code, no need to do that at compile-time: you can assemble the JS code as a string at runtime and then write it to a file somewhere, I guess. Something that I was thinking about is comparision of resulting syntax tree to check if it was correctly implemented. It would be great if different gramar parsers will output result in common format (JSON or XML for example) and it will be possiple to compare them for equality. But different parsers have different internal format of tree so maybe creating some transformation is possible. With this feature it could be possible to say if parser is working correctly. Different formats and also different languages. I don't see how you can compare a parse tree that's a D object and another tree made by dustjs: you never see the AST produced by dust, you only see the resulting JS code.
Re: Type deduction on templated constructor.
I expected such an answer and I do understand the decisions behind it. Yet, you gave me a really GOOD news! Having to write cast(ubyte) 1 was way too much verbose for my liking, while the new ubyte(1) is reasonable enough. Why not use `1u`?
Re: Type deduction on templated constructor.
On Wed, Jul 30, 2014 at 11:46 AM, Philippe Sigaud philippe.sig...@gmail.com wrote: I expected such an answer and I do understand the decisions behind it. Yet, you gave me a really GOOD news! Having to write cast(ubyte) 1 was way too much verbose for my liking, while the new ubyte(1) is reasonable enough. Why not use `1u`? Ow! Ignore that. 1u is an uint, not an ubyte.
Re: Compile time regex matching
I did, and I got it to work. Unfortunately, the code used to in the CTFE is left in the final executable even though it is not used at runtime. So now the question is, is there away to get rid of the excess baggage? Not that I know of. Once code is injected, it's compiled into the executable. auto result = MyRegex(import(config-file.txt)); // compile-time parsing return writeln(\~result.matches[0]~\);; mixin(get_match()); I never tried that, I'm happy that works. Another solution would be to push these actions at runtime, by using a small script instead of your compilation command. This script can be in D. - The script takes a file name as input - Open the file - Use regex to parse it - Extract the values you want and write them to a temporary file. - Invoke the compiler (with std.process) on your main file with -Jpath flag to the temporary file. Inside your real code, you can thus use mixin(import(temp file)) happily. - Delete the temporary file once the previous step is finished. Compile the script once and for all, it should execute quite rapidly. It's a unusual pre-processor, in a way.
Re: new properties for basic types
Halas, that's not what the OP wants. He needs properties on the *type* itself: int.foo instead of foo!int. So no, this is not possible.
Re: Compile time regex matching
I am trying to write some code that uses and matches to regular expressions at compile time, but the compiler won't let me because matchFirst and matchAll make use of malloc(). Is there an alternative that I can use that can be run at compile time? You can try Pegged, a parser generator that works at compile-time (both the generator and the generated parser). https://github.com/PhilippeSigaud/Pegged docs: https://github.com/PhilippeSigaud/Pegged/wiki/Pegged-Tutorial It's also on dub: http://code.dlang.org/packages/pegged It takes a grammar as input, not a single regular expression, but the syntax is not too different. import pegged.grammar; mixin(grammar(` MyRegex: foo - abc* def? `)); void main() { enum result = MyRegex(abcabcdefFOOBAR); // compile-time parsing // everything can be queried and tested at compile-time, if need be. static assert(result.matches == [abc, abc, def]); static assert(result.begin == 0); static assert(result.end == 9); pragma(msg, result.toString()); // parse tree } It probably does not implement all those regex nifty features, but it has all the usual Parsing Expression Grammars powers. It gives you an entire parse result, though: matches, children, subchildren, etc. As you can see, matches are accessible at the top level. One thing to keep in mind, that comes from the language and not this library: in the previous code, since 'result' is an enum, it'll be 'pasted' in place everytime it's used in code: all those static asserts get an entire copy of the parse tree. It's a bit wasteful, but using 'immutable' directly does not work here, but this is OK: enum res = MyRegex(abcabcdefFOOBAR); // compile-time parsing immutable result = res; // to avoid copying the enum value everywhere The static asserts then works (not the toString, though). Maybe someone more knowledgeable than me on DMD internals could certify it indeed avoid re-allocating those parse results.
Re: Compile time regex matching
On Mon, Jul 14, 2014 at 3:19 PM, Artur Skawina via Digitalmars-d-learn digitalmars-d-learn@puremagic.com wrote: On 07/14/14 13:42, Philippe Sigaud via Digitalmars-d-learn wrote: asserts get an entire copy of the parse tree. It's a bit wasteful, but using 'immutable' directly does not work here, but this is OK: enum res = MyRegex(abcabcdefFOOBAR); // compile-time parsing immutable result = res; // to avoid copying the enum value everywhere static immutable result = MyRegex(abcabcdefFOOBAR); // compile-time parsing Ah, static! The static asserts then works (not the toString, though). Maybe (snip diff) I'll push that to the repo, thanks! I should sprinkle some const and pure everywhere... [completely untested; just did a git clone and fixed the two errors the compiler was whining about. Hmm, did pegged get faster? Last time i tried (years ago) it was unusably slow; right now, compiling your example, i didn't notice the extra multi-second delay that was there then.] It's still slower than some handcrafted parsers. At some time, I could get it on par with std.regex (between 1.3 and 1.8 times slower), but that meant losing some other properties. I have other parsing engines partially implemented, with either a larger specter of grammars or better speed (but not both!). I hope the coming holidays will let me go back to it.
Re: new properties for basic types
Hmm. So how do I use stuff like this: template defaultInit(T) { static if (!is(typeof({ T v = void; })))// inout(U) @property T defaultInit(T v = T.init); else @property T defaultInit(); } (this is from std.traits - ok, it's private, but anyway) It should be invoked as `defaultInit!SomeType` Because I have seen nowhere anything like defaultInit!T (or T.defaultInit) and don't understand why here the attribute @property is used. Why does it make a difference, and how? @property allows you to call a function without the parenthesis (), to imitate a field in a struct or class. In this particular case, I don't know what defaultInit is used for. It seems to compile to a forward declaration of a function, but I don't know what for. I cannot find it on my copy of std.traits. What DMD version are you using?
Re: Opinions: The Best and Worst of D (for a lecture/talk I intend to give)
On Tue, Jul 8, 2014 at 7:50 AM, H. S. Teoh via Digitalmars-d-learn digitalmars-d-learn@puremagic.com wrote quite a wall of text Wow, what to add to that? Maybe you scared other from participating ;-) * I'll second metaprogramming: the alliance between templates, CTFE and mixins is really nice. It's *the* feature (or triplet of features) I think of when Walter says that many D parts are kind of what for? in isolation but really grow into something awesome by using one another. * I'd add static introspection to the mix: using static if, __traits(...) and is(...), clunky as the syntax is (there, one 'ugly' thing for you), is easy and very powerful: the idea to have code selecting its flow or extracting information (is that a static array? Does this aggregate have an '.empty' method?). This is the basis for std.algorithm idiom of 'static interface' which allows us compile-time duck typing, which I find very pleasing. * unittests are nice of course, H. S. Teoh already said it expressively enough :-) * I'd add arrays and slice. They are wonderfully simple to use, efficient, etc. I remember learning D by translating the Euler Project problems from C++ to D and it was a joy. Which brings me to another feature I like: ranges. The idea is nothing new, but I find it quite well-realized in D, far easier than other compiled languages alternatives and since they are pervasive in the library, you can really plug components into one another nicely. For example: http://wiki.dlang.org/Component_programming_with_ranges#Case_Study:_Formatting_a_Calendar * dub is good, and you can show code.dlang.org in your presentation. * Bonus point: different compilers. I like that. I regularly use at least two in parallel while developping (comparing results, speed, etc). Kudos to all the guys involved! As for the bad and ugly: * it's frustrating not to have a big collection module in Phobos, but then I didn't propose one, so I'll shut up. * there are still some not so nice interaction between const/shared/inout/ auto ref, though I rarely hit them these days * The compiler still has some quirks: I find it strange you can put unused qualifiers in many places. But very honestly, it was already a joy to use a few years ago, and it's becoming better and better.
Re: dependency graph
If you compile your project with the -deps flag, the compiler will output import dependencies. With -deps=filename, the output will go into filename. From there, you'll have to parse and create the graph, though. Maybe have a look into rdmd source, to see how the dependency extraction is done there?
Re: What exactly module in D means?
On Sat, Jul 5, 2014 at 6:35 PM, Andre Tampubolon via Digitalmars-d-learn digitalmars-d-learn@puremagic.com wrote: I've been reading the newsgroup for a while, and it seems that one of the reason folks like D is because it supports module. My question is: what does module mean? A quick google pointed my this page: http://dlang.org/module.html. Still cannot understand it, though :) How does it differ from the old C's #include? Well, module are 'more first-class' in D than in C. By this, I mean that they have an identity: a name, members, symbols. You can see them as a enormous struct/class. You can use introspection to obtain the symbols defined in a module, query their types, etc. Heck, in some cases, module names can even by used as arguments for templates. As others said, a D module is a unit of encapsulation: inside a module, functions, structs and classes can freely call one other and access their internal fields. Outside the module, only what's not private is visible. Thus, you can create complex, interdependent structures inside your module, but export only some parts for public access. This way, you control a module 'interface', its external frontier. Importing a module in D means the public symbols defined in the module become accessible in the importer. There is no need to import all visible symbols in your current scope: you can restrict your import to only one or two symbols, rename them, etc. That's much more powerful than C when it comes to name clashes. Different 'downstream' modules can import the same 'upstream' module, and choose to import different symbols. No need to do a big 'import everything in the current scope'. symbols names are also defined on a per-module basis: two different modules can have members with a similar name, without clash: just prefix the names with the module name to differentiate them (or rename one while importing). Also, `import foo;` is a statement, you can put it everywhere a statement is legit. That's a recent addition (ie, 1-2 year?), that Andrei likes to call 'Turtles all the way down' and is quickly becoming a D idiom: import a symbol near its use place: inside a function, a method, even inside an if branch: that avoid scope pollution and nicely documents where a symbol is necessary.
Re: How to test templates for equality?
Seeing his example, the OP wants a solution that works even for templates: template Test1(T) {} pragma(msg, instanceArgsOf!(Test1, Test1!int)); which fails because Test1!int is not a type (std.traits.isInstanceOf fails also, for the same reason). And is(symbol == Name!Args, Args...) does not work if Name!Args and symbol are not types. In this particular case, the only solution I know of is an awful hack: using .stringof and __traits(identifier, x) and then parse the strings: Name!(int, double[string]) and Name(T, U[V], U, V) and then the fun begins: in the general case, you must then equate the arguments lists (recursively). Philippe
Re: Trying to reproduce Node.js async waterfall pattern.. (Meta-programming)
Yes, the final callback is always called, but if an error is passed to the callback by any of the main steps in the sequence ladder, it will immediately jump to the final callback and not execute further steps. OK. What do you mean? The compiler does deduce the type of Funcs. If you look at where I call Waterfall() in main, you'll see I had to manually specify (Callback cb) instead of just (cb); since it didn't know that the Funcs... were of type AsyncFunc you can use std.typetuple.allSatisfy with a helper template: enum isAsyncFunc(T) = is(T == AsyncFunc); ... (Funcs...)(Funcs funcs) if (allSatisfy!(isAsyncFunc, Funcs)) { ... } (cb) { cb(null, one);} is possible, but that means it's a function template, not a function. You can get this syntax by making the callbacks template arguments, which means they must be known at compile-time. Is that OK with you or do you need the possibility to define the callbacks at runtime? The goal was to do as much as possible at compile time. Could you elaborate on this a bit. I guess the answer is, yes, it's okay with me. I mean, it's possible to get a (cb){ some code } syntax, but as that define a function template, it has no real type: it cannot be a runtime argument, only an alias template parameter. That means that all callbacks must be defined in your code, none can come from user input or runtime computation. I don't get it: none of your callbacks have a return type per se: they all return 'void'. Do you want callbacks that really return something? Yes, the callbacks at step0 should output a type in the result which is specific to step0, and then that type should be fed in as a secondary parameter to step1. I didn't get that far, as I was already stuck. OK, I get it. thanks for your patience! Well, we are there to explain :-) I'll have try and code something. If I can get it to work, I'll post it there.
Re: Trying to reproduce Node.js async waterfall pattern.. (Meta-programming)
On Mon, Jun 23, 2014 at 9:39 PM, Christian Beaumont via Digitalmars-d-learn digitalmars-d-learn@puremagic.com wrote: Each function is given a callback, that when called, steps the waterfall forward on to the next function to process. If an error is passed to the callback (instead of null), then the waterfall stops processing and calls the final callback at the end of the chain. Just to be sure: whether or not an error is passed to a callback, the final callback is always called? I mean, the last callback could also be called *only when something fails*, a bit like a default case in a switch, or an error-handling routine. 1) I can't see any way to get the compiler to deduce the type of Funcs What do you mean? The compiler does deduce the type of Funcs. I had an urge to somehow specialize the variadic Funcs... but I couldn't figure out any syntax to do that. What do you mean by 'specialize'? Well, because of that, I have to repeatedly say (Callback cb) instead of (cb). (cb) { cb(null, one);} is possible, but that means it's a function template, not a function. You can get this syntax by making the callbacks template arguments, which means they must be known at compile-time. Is that OK with you or do you need the possibility to define the callbacks at runtime? 2) I can't see a path to flow the output type of the previous callback to the input TLastResult for the next... so it's stuck on string :( I don't get it: none of your callbacks have a return type per se: they all return 'void'. Do you want callbacks that really return something? 3) I had to use a specialization to deal with the head case; (the first function doesn't have an input from a previous result). Minor, but niggly. You can test if func[0] takes one or two arguments: import std.traits: isCallable, ReturnType; static if (isCallable!(Func[0]) ReturnType!(Func[0]).length == 1)
Re: What is the correct way to forward method calls to the struct field?
On Sun, Jun 22, 2014 at 5:04 PM, monnoroch via Digitalmars-d-learn digitalmars-d-learn@puremagic.com wrote: There is also a problem: when i declare opDispatch to be private, i still have access to this forwarding from another package. Is it a bug or what? I don't know. I never used private in conjunction with a template. Let's hope someone more knowledgeable than me can answer this.
Re: What is the correct way to forward method calls to the struct field?
On Sun, Jun 22, 2014 at 5:02 PM, monnoroch via Digitalmars-d-learn digitalmars-d-learn@puremagic.com wrote: Thanks a lot! There is a problem though: when i pass incorrect parameters to such a method, it says, that S has no such field, which is a misleading error message. You can test the mixin with static if, like this: struct SomeT { int foo(double d) { return 0;} void bar(double d) { return;} } struct S { auto opDispatch(string name, Args...)(Args args) { static if (is(typeof(mixin((*iface). ~ name)(args return mixin((*iface). ~ name)(args); else pragma(msg, S. ~ name ~ cannot be called with arguments of type ~ Args.stringof); } SomeT** iface; } void main() { SomeT st; SomeT* st_p = st; SomeT** st_p_p = st_p; S s = S(st_p_p); s.foo(3.14); s.foo(abc); s.bar(abc, 3.14); }
Re: template mixins for boilerplate
Out of curiosity, why use a mixin template containing a string mixin instead of, well, directly injecting a string mixin in your struct, with a function?
Re: template mixins for boilerplate
On Sat, Jun 21, 2014 at 4:24 PM, Dicebot via Digitalmars-d-learn digitalmars-d-learn@puremagic.com wrote: On Saturday, 21 June 2014 at 13:45:14 UTC, Philippe Sigaud via Digitalmars-d-learn wrote: Out of curiosity, why use a mixin template containing a string mixin instead of, well, directly injecting a string mixin in your struct, with a function? Hiding non-hygienic implementation behind a more reliable interface. In what way is a template more reliable than the equivalent function? That's an honest question: I'm just looking at the code a few posts upward: mixin template Function(string name) { mixin(public static int ~ name ~ () { return other.module. ~ name ~; }); } struct S { mixin Function!fctn1; } And this double-mixin construction seems needlessly complicated to me, compared to: string Function(string name) { return public static int ~ name ~ () { return other.module. ~ name ~; }; } struct S { mixin(Function(fctn1)); }
Re: What is the correct way to forward method calls to the struct field?
You can use 'auto' to let the compiler deduce the return type. Here I use 'foo' which returns an int and 'bar', which returns void. struct SomeT { int foo(double d) { return 0;} void bar(double d) { return;} } struct S { auto /* here */ opDispatch(string name, Args...)(Args args) { return mixin((*iface). ~ name)(args); } SomeT** iface; } void main() { SomeT st; SomeT* st_p = st; SomeT** st_p_p = st_p; S s = S(st_p_p); import std.stdio : writeln; writeln(s.foo(3.14)); // 0 writeln(typeof(s.bar(3.14)).stringof); // void } On Sat, Jun 21, 2014 at 8:21 PM, monnoroch via Digitalmars-d-learn digitalmars-d-learn@puremagic.com wrote: On Saturday, 21 June 2014 at 18:16:17 UTC, monnoroch wrote: Actyaly, last variant didn't work either: i was testing it inside S like ifc.foo(1), so UFCS kiked in, not alias this. Oh, my bad, alias impl this; actually did work. But the first argument problem still holds.
Re: template mixins for boilerplate
Use a string mixin? string fun(string name) { return public static int ~ name ~ () { return 0; }; } struct S { mixin (fun(fctn1)); } void main() { S s; import std.stdio; writeln(s.fctn1()); }
Re: Universal Construction Syntax for Pointers?
Would auto i = (int*)(3); make sense? Does it work?
Re: Universal Construction Syntax for Pointers?
And I don't think it should, because the heap allocation that you're probably expecting should be explicit IMO. For me it's also unintuitive, because I would read it as constructing a pointer that points to the address 3. I agree. I'm trying to get a feel on the limits of this new 'type(value)' syntax.
Re: does there exist a dimensional analysis library for D?
Hi Vlad, you can try David Nadlinger's std.units: http://klickverbot.at/code/units/std_units.html See the discussion at http://forum.dlang.org/thread/io1vgo$1fnc$1...@digitalmars.com From what I deemly remember of Boost/units, it's a bit less complete, but far easier to use.
Re: one of the weirdest bugs ever - request for testing
// wrong code gen(*) with -release -O -inline -noboundscheck or // with -release -inline -noboundscheck but only if std.file is imported: auto x = countUntil( names, FOO ); write(x); if( 0 = x ) writeln( found a FOO); // (*) not found! } I'm running OSX Mavericks with DMD v2.065.0. This behavior cannot be reproduced. Linux, 64bits, DMD v2.065.0 Works OK for me (1 found a FOO), with or without importing std.file and compiling with -release -inline -noboundscheck
Re: Creating new types from tuples.
Is there any reason you couldn't (or would rather not) use structs rather than tuples? That would work. What would be the best way to auto-generate the types? I have somewhere around 30 already, and the number will grow with this project. Evan Davis Maybe you could use a struct template, with UDP as a template parameter. It'll instantiate a different type for each UDP value. If you add new possible values to the enum, the rest of the code will follow. struct SendReceivePair(UDP udp) { /// maybe here some different values, differentiated by static if, if needed. } Then, use these types directly in 'receive': receive( (SendReceivePair!(UDP.ping) value) { }, (SendReceivePair!(UDP.keep_alive) value) { } ) If you want to 'retrieve' the UDP template parameter, you can expose it through an alias: struct SendReceivePair(UDP udp) { alias packetType = udp; } So, given SendReceivePair!(xxx) srp, you can get 'xxx' by srp.packetType;
Re: When is a slice not a slice?
enum b = DataAndView(1); assert (!sameTail(b.data, b.view)); I suppose it's because enums are manifest constants: the value they represent is 'copy-pasted' anew everywhere it appears in the code. So for arrays and associative arrays, it means recreating a new value each and every time. In your case, your code is equivalent to: assert (!sameTail(DataAndView(1).data,DataAndView(1).view)); And the two DataAndView(1), being completely separated, do not have the same tail.
Re: enums
On Sat, May 31, 2014 at 10:14 PM, bearophile via Digitalmars-d-learn digitalmars-d-learn@puremagic.com wrote: In contrast to those two examples where immutable can be used at compile time, what are some other cases where it is necessary to use enum instead of immutable? By default use enum if you define a compile-time-known value (...) Now that we have immutable's that can be used inside templates, why use an enum? Because it's 'inlined' in the code? (I know the reason not to use it for an array or associative array, I experimented that fully in my own code. Ouch!)
Re: how to detect ctfe
But let's keep in mind it's a *runtime* value. You cannot use it at compile-time as a boolean for a 'static if'. So: if (__ctfe) // yes { // compile-time path } else { // runtime path } But not: static if (__ctfe) // no { // compile-time path, including new global declarations } else { // runtime path } Why would you want to do that? I needed an associative array for my code. AA don't work that well at compile-time. So I wanted to replace them with my own Associative struct, maybe less efficient/generic, but that works at CT. The idea was: static if (__ctfe) alias Type = Associative!(string, string); else alias Type = string[string]; // then, use Type, whatever the path.
Re: Casting Structs
On Sun, Jun 1, 2014 at 12:34 AM, Timon Gehr via Digitalmars-d-learn digitalmars-d-learn@puremagic.com wrote: This behaviour is independent of templates. Struct values of the same size can be reinterpret-cast to each other this way even if their types are completely unrelated. Do you know if this is by design?
Re: DMD fail when using both reflection and UDA
In any case, it's an internal compiler error, so it's a bug. Users should never see ICEs. Could you please report it, with the entire error message?
Re: Hiding types
On Sat, May 31, 2014 at 6:39 AM, Dicebot via Digitalmars-d-learn digitalmars-d-learn@puremagic.com wrote: private in D does not provide any strong guarantees, it only controls direct access to the symbol. You effectively want some sort of strict internal linkage attribute which does not exist in D. Indeed. I will learn to use '@disable this', then.
Re: Hiding types
What do you mean? Like this? Hidden* foo() { return new Hidden();} Yes, this way you can control all aspects of the construction and use. You wouldn't need to make it private even, just don't lay out the struct in the normal import: struct Hidden; I think you would need to use a .di file to do this. OK, I'll try that also. Thank you! You can make the struct's methods and data all private, which would prevent any useful access to it. But I don't know your use case. I was trying to imitate some Haskell code in D. The idea was to play with resources: from a File, create an OpenedFile which cannot be created except by calling File.open(). And only FileOpened has a .close() method. Or something like this, anyway. But I now realize that I was heading in a wrong direction: private is not the way to do that: I want the user to know OpenedFile exists. I just forbid him to create such a value except through File.open(). So I guess : struct OpenedFile { @disable this... } is the way to go. Now I just have to find an explanation on how to use this. I never touched this part of D.
Re: Forward reference to nested function not allowed?
See: http://dlang.org/function.html#variadicnested The second example explains that nested functions can be accessed only if the name is in scope.
Re: enums
In D enum can be used to define manifest constants. This means constants known at compile time. In practice for a double there isn't a lot of difference. In general you can't take the address of a manifest constant, unlike immutables. Because they do not exist as 'variables' or symbol in the generated code. They are directly replaced by their computed value. so : - enum : manifest constant, can be used as a template argument, as a static if operand or generally as a compile-time value. Indeed, a way to force compile-time function evaluation is to ask for an enum: enum result = foo(...); // foo(...) will be evaluated during compilation. - immutable : it's a real variable: you can initialize it (once) at runtime, and take its address.
Re: enums
A good use of 'static immutable', sadly not voted into the language. :-) But you're right, and I remember being tripped by this.
Re: enums
On Fri, May 30, 2014 at 7:28 PM, Ali Çehreli digitalmars-d-learn@puremagic.com wrote: On 05/30/2014 08:30 AM, Russel Winder via Digitalmars-d-learn wrote: enum double p0 = 0.0045; As others have already said, p0 is a manifest constant. Interestingly, it can be thought of like a C macro, being pasted inside source code. Avoid enums for arrays and associative arrays as they are hidden performance sinks. The constant gets regenerated at runtime every time it is used in an expression. I guess that, in an ideal world, immutable variables could be use at compile-time (template arguments, etc). We could then ditch 'enums-as-manifest-constants'.The best of both worlds. But what we have here is already quite good!
Re: enums
On Fri, May 30, 2014 at 7:56 PM, Steven Schveighoffer wrote: You can as long as the value is known at compile time: http://dpaste.dzfl.pl/5a710bd80ab0 Oh wow. And that works for static if also: http://dpaste.dzfl.pl/f87321a47834 Man. That opens some new possibilities.
Hiding types
I'm trying to 'hide' a type, so as not to see it outside its module. I want to control the way it's created and used. I know of Voldemort types and '@disable this', but for now I'm just trying to use 'private'. Halas, it seems it can be circumvented: * module A; private struct Hidden {} Hidden foo() { return Hidden();} * module B; import A; void main() { typeof(foo()) h; } * Am I misunderstanding something or is that a bug?
Re: Hiding types
On Friday, 30 May 2014 at 19:54:00 UTC, safety0ff wrote: On Friday, 30 May 2014 at 19:50:43 UTC, Philippe Sigaud wrote: Am I misunderstanding something or is that a bug? Try: auto foo() { return Hidden();} I'm not seeing any difference? I'm still able to create a value of type Hidden in an external module.
Re: Hiding types
On Friday, 30 May 2014 at 20:02:40 UTC, Steven Schveighoffer wrote: If you want an opaque struct, you need to return it by pointer. What do you mean? Like this? Hidden* foo() { return new Hidden();} ? Otherwise, the user must be able to know what type it is (otherwise, how would he use it?) I just fear that by using internal, public, functions, the user might get access to a private type. I guess the D answer to that is to make foo private also. That makes sense. I now realize that I implicitly considered 'private' to be transitive (or viral). That is that: Hidden foo() { return Hidden();} as foo is returning a value from a private type, it should be considered private also. By the compiler, I mean.
Re: How to get struct's members ?
On Fri, May 23, 2014 at 8:44 AM, monarch_dodra via Digitalmars-d-learn digitalmars-d-learn@puremagic.com wrote: On Friday, 23 May 2014 at 01:17:18 UTC, bioinfornatics wrote: I would like to get struct's members and zip them with an action tupleof will do what you need (mostly). However, I don't think there will be any way to (generically) run-time zip on the members, due to probably type mismatch, and memory layout. In any case, nothing trivial, AFAIK. You can define a map-like (or zip-like) template to act on tuples as if they were ranges, but the resulting type will still be a tuple: in general, the members and the delegates associated with them will all have a different type. Bioinfornatics, if you know your struct members are all of the same type, you can 'cast' the tuple as an array by wrapping it in square brackets like this: [ myStruct.tupleof ] and then use the usual range algorithms. If that's not the case, you can create another struct, holding both the original struct and the delegates... I did some generic range-like work on tuples a few years ago. See for example: https://github.com/PhilippeSigaud/dranges/blob/master/tuple.d#L620 Could you explain what you want with more details?
Re: Avoiding __traits(getAttributes, ...) on alias
Vlad Levenfeld: but beware I've noticed that sometimes this is not equivalent to the previous version and I'm not sure how or why that happens. In particular I notice that mixin(const bool value = ~expr~;)); and const bool value = mixin(expr); are not the same, for some reason. What are the differences?
Re: Avoiding __traits(getAttributes, ...) on alias
else // doesn't compile, member is not accessible error foreach (type; __traits (getAttributes, mixin(`T.`~member))) static if (is (type == attribute)) return true; return false; Maybe its trying to use it inside of __traits that is causing it? Maybe __traits is trying to extract attributes from the mixin expression, before the mixin injection? That looks like a bug to me, no?