Re: trick to make throwing method @nogc
On Saturday, 25 February 2017 at 19:59:29 UTC, ikod wrote: Hello, I have a method for range: struct Range { immutable(ubyte[]) _buffer; size_t _pos; @property void popFront() pure @safe { enforce(_pos < _buffer.length, "popFront from empty buffer"); _pos++; } } I'd like to have @nogc here, but I can't because enforce() is non-@nogc. I have a trick but not sure if it is valid, especially I don't know if optimization will preserve code, used for throwing: import std.string; struct Range { immutable(ubyte[]) _buffer; size_t _pos; this(immutable(ubyte[]) s) { _buffer = s; } @property void popFront() pure @safe @nogc { if (_pos >= _buffer.length ) { auto _ = _buffer[$]; // throws RangeError } _pos++; } } void main() { auto r = Range("1".representation); r.popFront(); r.popFront(); // throws } Is it ok to use it? Is there any better solution? Thanks! You can wrap a gc function in a nogc call using a function pointer that casts it to a nogc. You do this first by casting to void* then back to the same signature as the function + @nogc. This "tricks" the compiler in to calling the gc function from a nogc function. The problem is, of course, it is not safe if the gc is turned off as it will result in a memory leak. This may or may not be an issue with enforce depending on if it allocates before or after the check.
Re: simple static if / traits question...
There are a few options: 1. static if(audio) 2. version(audio) 3. if (audio) It looks like you are trying to create the version(audio) semantic(if exists then use, else don't). Ultimately, though, if you are trying to make a binary that can either use audio or not depending on where it is ran, you'll have to stick to using actual run time variables and probably be a bit more organized about it. option 1 is the one I was shooting for. does the static if (audio) just check for the existence of audio, or does it also check to see if audio is true as well? Yes, but it checks at compile time. So the code will be evaluated by the compiler and if audio is true, it will only compile in the code in the if block. e.g, static if (audio) { do something } will be identical, in the binary, to do something if audio is true. The static if is an if statement and works like any ordinary if statement, but since you are using static(known at compile time) information then static if can actually be computed/evaluated at compile time(since all the inputs are know and cannot be changed)
Re: simple static if / traits question...
On Wednesday, 22 February 2017 at 21:27:47 UTC, WhatMeWorry wrote: I'm doing conditional compilation using static ifs like so: enum bool audio = true; // if audio flag is present and set to true, add to code build static if ( (__traits(compiles, audio)) && audio) playSound(soundSys, BLEEP ); This works, but I thought there might be a simpler way. For instance, after perusing std.traits, I thought I would find something like isPresent(audio) or isSymbol(audio) templates. Or am I being obtuse here? Thanks. You do realize that audio is a compile time constant? This means that in the binary, everything that depends on it is evaluated(as it can be, since it is known). This means that whatever app you are using will not be able to be able to "adapt" to the system changes. In this case, if the system has audio there is no way for the binary to use it because you compiled it out(if audio = false). In such a case you do not want to use a static or compile time variable unless you plan on creating multiple binaries. If your example above was just for demo then yes, you can do that but compiles is not what you want. Compiles only checks if the statement that follows is compilable as valid D code and it doesn't have anything to do with the value of the variables. There are a few options: 1. static if(audio) 2. version(audio) 3. if (audio) It looks like you are trying to create the version(audio) semantic(if exists then use, else don't). Ultimately, though, if you are trying to make a binary that can either use audio or not depending on where it is ran, you'll have to stick to using actual run time variables and probably be a bit more organized about it.
Re: scope with if
On Friday, 17 February 2017 at 20:06:19 UTC, berni wrote: I wonder if it's possible to do something like this: import std.stdio; void main(string[] args) { if (args[1]=="a") { write("A"); scope (exit) write("B"); } write("C"); } I expected the output to be ACB not ABC. I understand, that the scope ends at the end of the if, but I wonder, if it's possible to have a "conditional scope" or something like this. I found a workaround using "finally", but anyway I'm curious. could be useful to have something like scope(final) that would be the "final scope"
Re: Can't iterate over range
On Saturday, 4 February 2017 at 14:35:37 UTC, ag0aep6g wrote: On 02/04/2017 12:31 PM, Profile Anaysis wrote: I am trying to iterate over the combinations of a set using the code https://rosettacode.org/wiki/Power_set#D I have an array which I call powerSet on and I get a result of MapResult. I have tried to foreach or front/popFront and even each() on it but I can never get the result as the same array type that I started with. To create an array from a range, you can use std.array.array: http://dlang.org/phobos/std_array.html#.array What is MapResult(the algorithm that generates the result lazily?) Yes, it's a struct that gives you one element at a time, lazily generated. and how do we easily iterate over the results like we would with an array? foreach and empty/front/popFront should both work. If you can't get them to work, show what you tried. well, I simply took the code from the page I linked and did a front() on the MapResult and it say the type was wrong. I thought it would give me the type I put in which was an array. I guess maybe I needed to convert it to an array though... but I didn't try. I moved on it iterating over it manually. someStruct[] X; someStruct[] x = powerSet(X).popFront(); gave me an error. Was saying I was getting another MapResult, which I thought it shouldn't but maybe I just needed to convert it to an array.
Can't iterate over range
I am trying to iterate over the combinations of a set using the code https://rosettacode.org/wiki/Power_set#D I have an array which I call powerSet on and I get a result of MapResult. I have tried to foreach or front/popFront and even each() on it but I can never get the result as the same array type that I started with. What is MapResult(the algorithm that generates the result lazily?) and how do we easily iterate over the results like we would with an array?
module specification for variables
I'd like to have a global variable in a module but it must be accessed by the module name outside of the module. Sort of like a static variable in a class. private blocks it completely and public will allow it to be imported in to the global scope. Haven't tried protected but I assume that is meaningless. Basically it is a sort of module initialization variable that only needs to be set once(usually) outside the module. So I do not want it to be imported in to other modules scope in any way, ever(there is no need so why create potential issues). module x; special int X; // special = some keyword that makes this work as I intend. e.g., "no_import int X;" module y; void main() { import x; x.X = 3; // X = 3; fails. } I know you can say that one can used a named import and all that but that isn't the point(I want all the other stuff imported as it would be) I could create a static class, for example, and go through that... but seems like a hoop to jump through.
Re: Fiber overhead
On Saturday, 4 February 2017 at 06:54:01 UTC, Ali Çehreli wrote: On 02/03/2017 08:47 PM, Profile Anaysis wrote: What is the overhead of using a fiber? The performance overhead of call() and yield() are comparable to function calls because it's simply a few register assignments in each case. (Change the stack pointer, etc.) Memory overhead is memory for call stack, size of which can be determined by the programmer. Ali Thanks, that was what I was hoping.
Fiber overhead
What is the overhead of using a fiber?
Re: Yield from function?
On Tuesday, 31 January 2017 at 11:31:28 UTC, Ali Çehreli wrote: On 01/31/2017 03:00 AM, Profile Anaysis wrote: > [...] [...] > [...] return type. Options: [...] Thanks again!
Re: Yield from function?
On Tuesday, 31 January 2017 at 06:32:02 UTC, Ali Çehreli wrote: On 01/30/2017 08:12 PM, Profile Anaysis wrote: import std.stdio, std.concurrency, core.thread; class Search : Fiber { this() { super(&start); } int res = 0; void start() { Fiber.yield(); res = 1; } } void main() { auto search = new Search(); search.call(); writeln(search.res); search.call(); writeln(search.res); search.call(); writeln(search.res); // crashes after 3rd call(first two work fine) } That's because the fiber is not in a callable state. (You can check with search.state.) Here is one where the fiber function lives (too) long: import std.stdio, std.concurrency, core.thread; class Search : Fiber { this() { super(&start); } int res = 0; void start() { while (true) { Fiber.yield(); ++res; } } } void main() { auto search = new Search(); foreach (i; 0 .. 5) { search.call(); writeln(search.res); } } Ali Just curious, how can I use start() recursively? I would like to iterate over a recursive structure and yield for each "solution". I could use a stack to store the values but the whole point of the fiber was to avoid that. void start() { while (true) { Fiber.yield(); ++res; } } Seems I can't create start with a parameter and non-void return type. This seems to make it about useless to use a fiber recursively because no pushing and popping on the stack occur. class Search : Fiber { this() { super(&start); } bool End = false; int res = 0; void start() { while (!End) { int Foo(int x) { Fiber.yield(); if (x < 10) { res = Foo(x++); return res; } else return x; } } } void main() { auto search = new Search(); foreach (i; 0 .. 5) { search.call(); writeln(search.res); } search.End = true; } My goal is simple, to yield a solution at each step in the recursive process. Maybe I can use another fiber using the lambda syntax?
Re: Yield from function?
On Tuesday, 31 January 2017 at 06:32:02 UTC, Ali Çehreli wrote: On 01/30/2017 08:12 PM, Profile Anaysis wrote: [...] That's because the fiber is not in a callable state. (You can check with search.state.) Here is one where the fiber function lives (too) long: import std.stdio, std.concurrency, core.thread; class Search : Fiber { this() { super(&start); } int res = 0; void start() { while (true) { Fiber.yield(); ++res; } } } void main() { auto search = new Search(); foreach (i; 0 .. 5) { search.call(); writeln(search.res); } } Ali Thanks.
Re: Yield from function?
On Monday, 30 January 2017 at 18:48:10 UTC, Ali Çehreli wrote: On 01/30/2017 03:03 AM, Profile Anaysis wrote: > I need to yield from a complex recursive function too allow visualizing > what it is doing. > > e.g., if it is a tree searching algorithm, I'd like to yield for each > node so that the current state can be shown visually. I used tree iteration as a Generator example here: http://ddili.org/ders/d.en/fibers.html It's in the code where the function 'byNode' appears. (The example builds on an earlier tree iteration code in the same chapter.) Ali I tried your lambda based fib example and it works as expected(using a function) But when I try the class version it crashes without a call stack or any info(somewhere in the fiber module and an access violation). import std.stdio, std.concurrency, core.thread; class Search : Fiber { this() { super(&start); } int res = 0; void start() { Fiber.yield(); res = 1; } } void main() { auto search = new Search(); search.call(); writeln(search.res); search.call(); writeln(search.res); search.call(); writeln(search.res); // crashes after 3rd call(first two work fine) } Any ideas what why it is crashing like this?
Re: Yield from function?
On Monday, 30 January 2017 at 22:34:11 UTC, TheFlyingFiddle wrote: On Monday, 30 January 2017 at 11:03:52 UTC, Profile Anaysis wrote: I need to yield from a complex recursive function too allow visualizing what it is doing. e.g., if it is a tree searching algorithm, I'd like to yield for each node so that the current state can be shown visually. I realize that there are several ways to do this but D a yield version without additional threads would be optimal. I don't need concurrency or speed, just simple. If you don't want to use fibers then an alternative to yeilds is to use callbacks during iteration. Example: struct Tree(T) { T value; Tree!(T)[] children; } void iterDepth(T)(Tree!(T) tree, void delegate(Tree!T) cb) { cb(tree); foreach(child; tree.children) { iterDepth(child, cb); } } unittest { auto tree = ... //Make the tree somehow iterDepth(tree, (node) { writeln(node.value); }); } Callbacks have their set of problems but it's one of the simpler ways to do this. This can't be easily because it requires the callback to contain the main program(if it depends on the results). Since I am already in a multi-threaded environment it would not be easy to marshal the data around. If I run it in it's own thread then it won't block but seems like a lot of work for a simple thing.
Yield from function?
I need to yield from a complex recursive function too allow visualizing what it is doing. e.g., if it is a tree searching algorithm, I'd like to yield for each node so that the current state can be shown visually. I realize that there are several ways to do this but D a yield version without additional threads would be optimal. I don't need concurrency or speed, just simple.
Bug in generator
the code from https://dlang.org/library/std/concurrency/generator.html gives a seg fault at the end. import std.concurrency; import std.stdio; void main() { auto tid = spawn( { while (true) { writeln(receiveOnly!int()); } }); auto r = new Generator!int( { foreach (i; 1 .. 10) yield(i); }); foreach (e; r) { tid.send(e); } } 0x7FF7BDDA05E5 in std.concurrency.receiveOnly!int.receiveOnly.__lambda3 at \..\..\src\phobos\std\concurrency.d(805) 0x7FF7BDDA1997 in void std.concurrency.Message.map!(pure @nogc @safe void function(std.concurrency.OwnerTerminated)*).map(pure @nogc @safe void function(std.concurrency.OwnerTerminated)*) at \..\..\src\phobos\std\concurrency.d(163) 0x7FF7BDDA0B04 in D3std11concurrency10MessageBox160__T3getTDFNaNbNiNfiZvTPFNaNiNfC3std11concurrency14LinkTerminatedZvTPFNaNiNfC3std11concurrency15OwnerTerminatedZvTPFS3std7variant18__T8VariantNVmi20Z8VariantNZvZ3getMFDFNaNbNiNfiZvPFNaNiNfC3std11concurrency14LinkTerminatedZvPFNaNiNfC3std11concurrency15OwnerTerminatedZvPFS3std7variant18__T8VariantNVmi20Z8VariantNZvZ13onStandardMsgMFKS3std11concurrency7MessageZb 0x7FF7BDDA0EA0 in D3std11concurrency10MessageBox160__T3getTDFNaNbNiNfiZvTPFNaNiNfC3std11concurrency14LinkTerminatedZvTPFNaNiNfC3std11concurrency15OwnerTerminatedZvTPFS3std7variant18__T8VariantNVmi20Z8VariantNZvZ3getMFDFNaNbNiNfiZvPFNaNiNfC3std11concurrency14LinkTerminatedZvPFNaNiNfC3std11concurrency15OwnerTerminatedZvPFS3std7variant18__T8VariantNVmi20Z8VariantNZvZ13onLinkDeadMsgMFKS3std11concurrency7MessageZb at \..\..\src\phobos\std\concurrency.d(1988) 0x7FF7BDDA0F4A in D3std11concurrency10MessageBox160__T3getTDFNaNbNiNfiZvTPFNaNiNfC3std11concurrency14LinkTerminatedZvTPFNaNiNfC3std11concurrency15OwnerTerminatedZvTPFS3std7variant18__T8VariantNVmi20Z8VariantNZvZ3getMFDFNaNbNiNfiZvPFNaNiNfC3std11concurrency14LinkTerminatedZvPFNaNiNfC3std11concurrency15OwnerTerminatedZvPFS3std7variant18__T8VariantNVmi20Z8VariantNZvZ12onControlMsgMFKS3std11concurrency7MessageZb at \..\..\src\phobos\std\concurrency.d(2000) 0x7FF7BDDA0FFA in D3std11concurrency10MessageBox160__T3getTDFNaNbNiNfiZvTPFNaNiNfC3std11concurrency14LinkTerminatedZvTPFNaNiNfC3std11concurrency15OwnerTerminatedZvTPFS3std7variant18__T8VariantNVmi20Z8VariantNZvZ3getMFDFNaNbNiNfiZvPFNaNiNfC3std11concurrency14LinkTerminatedZvPFNaNiNfC3std11concurrency15OwnerTerminatedZvPFS3std7variant18__T8VariantNVmi20Z8VariantNZvZ4scanMFKS3std11concurrency36__T4ListTS3std11concurrency7MessageZ4ListZb at \..\..\src\phobos\std\concurrency.d(2016) 0x7FF7BDDA094C in bool std.concurrency.MessageBox.get!(pure nothrow @nogc @safe void delegate(int), pure @nogc @safe void function(std.concurrency.LinkTerminated)*, pure @nogc @safe void function(std.concurrency.OwnerTerminated)*, void function(std.variant.VariantN!(20uL).VariantN)*).get(pure nothrow @nogc @safe void delegate(int), pure @nogc @safe void function(std.concurrency.LinkTerminated)*, pure @nogc @safe void function(std.concurrency.OwnerTerminated)*, void function(std.variant.VariantN!(20uL).VariantN)*) at \..\..\src\phobos\std\concurrency.d(2115) 0x7FF7BDDA0579 in std.concurrency.receiveOnly!int.receiveOnly at \..\..\src\phobos\std\concurrency.d(806) 0x7FF7BDD9F50D in main.main.__lambda1 at main.d(82) 0x7FF7BDDA46C2 in std.concurrency._spawn!(void function())._spawn.exec at \..\..\src\phobos\std\concurrency.d(538) 0x7FF7BDDE9302 in void core.thread.Thread.run() 0x7FF7BDDD5CBD in thread_entryPoint 0x7FF7BDE5D96D in thread_start__ptr64)> at d:\th\minkernel\crts\ucrt\src\appcrt\startup\thread.cpp(115) 0x7FF9EB178364 in BaseThreadInitThunk 0x7FF9EBD570D1 in RtlUserThreadStart Also, if one tries to create a global generator an error about PAGESIZE not being a compile time value is given.
Min, max of enum
Since we do not have attributes for enums, I use _ in front of the names for meta values. I need to get the non-meta values for the enum so I can iterate over it and use it properly. enum myEnum { _Meta1 = 0, A,B,C, _Meta3 = 43, D = 3, } The num, for all practical purposes does not contain _Meta1, and_Meta3. But in code I use to!myEnum(intI) and having the meta values complicate things(simple shifting may or may not work). I also need to create array indexers based on myEnum that don't include the meta characters. What I do a lot is convert integers in to fields of the enum. If I do not include any Meta, then it is straight forward to!myEnum(i), but with them it is not, so doing things like int[myEnum] x; x[to!myEnum(i))] is difficult because the conversion will be invalid for meta. I'd have to do some work on i to get the 0-n representation to map properly in to the enum... basically avoiding the meta fields. This would all be solved with attributes for enums, but that, I suppose is a pipe dream. Any ideas how I can make this easy?
Re: Trying to understand multidimensional arrays in D
On Thursday, 26 January 2017 at 03:02:32 UTC, Jonathan M Davis wrote: On Thursday, January 26, 2017 01:47:53 Profile Anaysis via Digitalmars-d- learn wrote: [...] Like in C/C++, types are mostly read outward from the variable name in D. In both C/C++ and D, [...] Actually, I think the notation is simply wrong. // Matrix order testing auto x = new int[][][][](1,2,3,4); auto y = new int[1][2][][](3,4); for(int i = 0; i < 1; i++) for(int j = 0; j < 2; j++) for(int k = 0; k < 3; k++) for(int l = 0; l < 4; l++) { x[i][j][k][l] = i*j*k*l; //x[l][k][j][i] = i*j*k*l; //y[i][j][k][l] = i*j*k*l; //y[l][k][j][i] = i*j*k*l; y[k][l][j][i] = i*j*k*l; } It is inconsistent with dynamic arrays and mixing them creates a mess in the order of indices. I best someone was asleep at the wheel when programming the code for static arrays. (probably someone different than who programmed the dynamic arrays) This is a bug IMO.(unfortunately one that can't be fixed ;/)
Re: Trying to understand multidimensional arrays in D
On Thursday, 26 January 2017 at 03:02:32 UTC, Jonathan M Davis wrote: On Thursday, January 26, 2017 01:47:53 Profile Anaysis via Digitalmars-d- learn wrote: [...] Like in C/C++, types are mostly read outward from the variable name in D. In both C/C++ and D, [...] Thanks. I'll just have to play around with them a bit until it sinks in. I think my problem was declaring them wrong which would always lead to weird errors. I am using static arrays because the size of the matrix is fixed. I need to allocate them though because that is what my matrix_history contains. I guess I can do that with new int[n][n] type of thing? (I think I tried that before. Anyways, probably would work fine now but I already move don to wrapping it in a struct. It provides more flexibility in my case.
Re: Trying to understand multidimensional arrays in D
On Thursday, 26 January 2017 at 02:29:07 UTC, Ivan Kazmenko wrote: On Thursday, 26 January 2017 at 01:47:53 UTC, Profile Anaysis wrote: does this mean that have int[][4][4] matrix_history; backwards? int[4][4][] matrix_history; this creates even a more set of problems. In short, you are right, `int[4][4][]` is a dynamic array of `int[4][4]`. In turn, `int[4][4]` is a static length-4 array of `int[4]`, and that is a static length-4 array of `int`. It's quite logical once you learn how to read it: if T is a type, then T[] is a dynamic array of that type, and T[4] is a static length-4 array of that type. So, if I have `int[2][5][7] a;` somewhere, the very last element is `a[6][4][1]`. If you are inclined to think in terms of this difference, the simple rule of thumb would be that the order of dimensions in the declaration is reversed. Thanks, knowing the last element is important ; Basically I just need to know the proper index. For me, having the array declared in symbolic form that matches the indexing, like in C/C++, is quicker, easier to remember, and harder to forget. I don't really care too much beyond that. They could be declared any way... but I find myself getting confused in D because of little things like this that don't carry over while almost everything else is. Also, note that if you want to have, for example, a dynamic array of 5 dynamic arrays of the same length 7 (modeling a C rectangular array, or a D static array, but with possibility to change the length of each row, as well as the number of rows), you would go with `auto a = new int [] [] (5, 7);` (initialization) The static array of 5 static arrays of length 7 is still `int [7] [5] a;` (type declaration) So the reverse only happens in type declarations. (On the contrary, declarations in C or C++ looks rather unintuitive from this perspective: `T a[4][5][6]` is means that `a` is an array of 4 arrays of 5 arrays of 6 arrays of `T`. Note how we have to read left-to-right but then wrap around the string to get the meaning.) lol, I don' tknow what the last sentence means. wrap around the string? Do you mean look at the variable? For me the interpretation above is the most logical because it is a sequential operation in my mind, if you will. x of y of z and the chain can be cut off anywhere and the interpretation still be the same. Since I am a native speaker of English, which is a left to right language, it just makes sense. I, am, of coursed biased because I started with C/C++ rather than D. Additionally, reading about various kinds of arrays in D might help: https://dlang.org/spec/arrays.html And more in-depth material about array slicing: http://dlang.org/d-array-article.html Ivan Kazmenko.
Trying to understand multidimensional arrays in D
I'm a bit confused by how D does arrays. I would like to create a array of matrices but I do not seem to get the correct behavior: int[][4][4] matrix_history; What I would like is to have a 4x4 matrix and have a history of it. Just n 4x4 matrices but each matrix is a fixed size but there can be an arbitrary(dynamic) number. I would like, for example, matrix_history[0] to be the first 4x4 matrix, matrix_history[1] to be the second 4x4 matrix, ... and I would, in fact, like to be able to append a matrix like matrix_history ~= some_4x4matrix. I try to assign like matrix_history[total-1] = new int[][](8,8); or append matrix_history ~= new int[][](4,4); but the append fails with Error: cannot append type int[][] to type int[][4][4] which is confusing because the type per entry in the matrix history is of type int[][]. e.g., I could wrap the int[][] in a struct and then just have a singular array of these matrices and, to me, the logic should be the same. e.g., struct matrix { int[4][4] data; } then matrix[] matrix_history. and matrix_history ~= new matrix; so, the logic should be the same between two. This method works but the more direct method doesn't seem to. If I do auto x = matrix_history[0]; x is not a int[4][4] but of type int[4](as reported by the debugger), which is very confusing. it seems that the way D indexes multidimensional arrays is not logical nor consistent from my perspective. auto x = matrix_history[0] returns an array of size 4. auto x = matrix_history[0][0] returns an 2d array of size 4x4. auto x = matrix_history[0][0][0] returns an int(as expected). does this mean that have int[][4][4] matrix_history; backwards? int[4][4][] matrix_history; this creates even a more set of problems. I guess I will have to revert to wrapping the matrix in a struct to get the natural extension of single arrays unless someone can clue me in on what is going on.
Re: Can compiler profile itself?
On Wednesday, 25 January 2017 at 12:49:05 UTC, Stefan Koch wrote: On Tuesday, 24 January 2017 at 23:25:12 UTC, Profile Anaysis wrote: I am trying to compile some code and it takes around 6 seconds. Even if I change one line in one module, it takes the same time. There are about 20 different d modules. [...] yes the compiler can be used to profile itself. build it with make ENABLE_PROFILE=1 If your code is overly slow you are probably using recursive variaidic templates. Would it not be easier to have this feature as a command line argument that enables it in the compiler or include a compiler version that does this? Not all everyone is good at building from sources...
Can compiler profile itself?
I am trying to compile some code and it takes around 6 seconds. Even if I change one line in one module, it takes the same time. There are about 20 different d modules. I used to get around 1-2 second compile times several months ago on different projects. I did upgrade a few things and it seems that something has made things slow. Can we ask the compiler what seems to be taking the most time(a module, a template, etc...)? If the compiler can profile itself then it would be very easy to figure out what is slowing things down in compilation. I feel that I should be able to compile all the modules separately and only have to recompile the module that I changed... and that it should be quite fast(e.g., if the module contains nothing but the main and a write statement, regardless of all the other stuff in the project, I'd expect that to be fast). For example, If I do the import std.stdio; int main(string[] argv) { writeln("Hello D-World!"); return 0; } it takes <1s. Yet if I import a bunch of modules it takes 6+s and the time never reduces on subsequent builds. I am using Visual D. Visual D has a separate compile and link feature but when I try it for dmdx64 I get Internal error: backend\mscoffobj.c 2016 It does work for x32 but the speed does not change. I'm convinved that dmd is recompiling everything each time... and this doesn't seem very fast IMO when less than 0.1% of the project has changed.
Re: Is it possible to "cache" results of compile-time executions between compiles?
On Tuesday, 24 January 2017 at 21:36:50 UTC, Profile Anaysis wrote: ... Maybe with all this talk of the new CTFE engine being developed, a similar mechanism can be used optionally? This could help with debugging also. In debug mode, the cfte mixin's are written to disk with hash, if they are not a string themselves. (could be done with all cfte's, I suppose, but not sure about performance and consistency) Then debuggers can use the outputed cfte's for proper analysis, line breaking, etc...
Re: Is it possible to "cache" results of compile-time executions between compiles?
On Tuesday, 24 January 2017 at 16:49:03 UTC, TheFlyingFiddle wrote: On Tuesday, 24 January 2017 at 16:41:13 UTC, TheFlyingFiddle wrote: Everything turned out s much better than expected :) Added bonus is that mixin output can be viewed in the generated files :D Could you post your solution? I suggest we get a real caching module like above that has the extra feature of hashing the mixin strings. This way the caching mechanism can validate if the mixin strings have changed. Put the hash in a comment in the output file that used to test if the input string has the same hash. If it does, simply use the output file, else, regenerate. Adds some overhead but keeps things consistent. (Since I'm not sure what Cache!() is, I'm assuming it doesn't do this)