Re: Confusion about `Random`
On Fri, Dec 23, 2022 at 03:21:24PM +, jwatson-CO-edu via Digitalmars-d-learn wrote: > On Friday, 23 December 2022 at 00:00:06 UTC, H. S. Teoh wrote: [...] > > My personal guess is that you forgot a `ref` somewhere when you pass > > the RNG to a function. Given that due to historical accident > > std.random uses structs for RNG implementations, and this can > > sometimes lead to unexpected results when you unintentionally passed > > an RNG state by value instead of by reference. One thing to try > > could be to scan all your function signatures where an RNG is > > passed, and make sure there's a `ref` on it. [...] > I had not passed the RNG in any case, but instead accessed the global > RNG from inside any function that uses it. Is that a potential issue? Hmm, in that case it's probably not a problem with `ref`. You probably should give DustMite a shot; from the snippets you've posted so far we haven't found any clues of what might have gone wrong. To narrow down the issue we really need to start from the original code and reduce it to a minimal case. https://github.com/CyberShadow/DustMite T -- Дерево держится корнями, а человек - друзьями.
Re: Preventing nested struct destructor accessing stack frame
On 12/16/22 7:17 AM, Nick Treleaven wrote: This code segfaults when the GC calls the dtor after the unittest succeeds: ```d unittest { int i; struct S { ~this() { i++; } } (*new S).destroy; } ``` It seems destroy clears the context pointer. Is there a way to test if the context pointer is null in the dtor, to prevent the increment? Check if the struct is the init value? ```d ~this() { if(this !is this.init) ++i;} ``` Not ideal I guess, because really it's the context pointer you care about. -Steve
Re: Confusion about `Random`
On 12/23/22 10:07 AM, jwatson-CO-edu wrote: On Friday, 23 December 2022 at 00:58:01 UTC, Steven Schveighoffer wrote: Without the rest of the code, and how random is called, I have a hunch... Are you using threads by any chance? If, for instance, your calls to rand01 are done in a new thread, that new thread will have a *default* state of Mt19937. Good question, Steve, but I do not intentionally start any threads. Below is the machinery that interprets a for-loop. Do you see anything that would enclose a previous state of the RNG? Your code looks like it's making a function pointer, and that function pointer directly uses the global RNG. I'm not seeing how your code could be copying the RNG somehow, as I'm assuming it's not manipulating the generated code from the compiler. If it's not a threading problem, the only other possibility I can think of is that your loop code is not truly calling that function over and over. I'd start instrumenting rand01 with some printouts, and see if it's doing what you expect. If it's not, throw and catch an exception, and print the stack trace (or use a debugger) to help understand what is happening. I have been puzzled in the past with behavior that seemed to be reasonable, but given the way the implementation happened, did unexpected things (like caching values). -Steve
Re: Confusion about `Random`
On Friday, 23 December 2022 at 00:00:06 UTC, H. S. Teoh wrote: You could try using DustMite to reduce it to a minimal (or at least smaller) example. My personal guess is that you forgot a `ref` somewhere when you pass the RNG to a function. Given that due to historical accident std.random uses structs for RNG implementations, and this can sometimes lead to unexpected results when you unintentionally passed an RNG state by value instead of by reference. One thing to try could be to scan all your function signatures where an RNG is passed, and make sure there's a `ref` on it. T I had not passed the RNG in any case, but instead accessed the global RNG from inside any function that uses it. Is that a potential issue?
Re: Confusion about `Random`
On Friday, 23 December 2022 at 07:25:23 UTC, Salih Dincer wrote: You can try using static this. ```d import std.random; static this() { } // can try using Mt19937 rnd; void init_random() { rnd = Random(unpredictableSeed); } double rand01() { return uniform(0, 1.0, rnd); } void main() { init_random(); struct Atom { double num; } alias atom = Atom* function(); atom[string] primitiveSymbols = [ "rand" : () => new Atom(rand01) ]; import std.stdio; writeln(*primitiveSymbols["rand"]()); // Atom(0.630001) } ``` SDB@79 Salih, I would like to implement this tactic, but I do not understand it. What are you creating here? ```d static this() { } // can try using ``` What is this operator? ```d \*...*\ () => new Atom(rand01) \*...*\ ```
Re: Confusion about `Random`
On Friday, 23 December 2022 at 00:58:01 UTC, Steven Schveighoffer wrote: Without the rest of the code, and how random is called, I have a hunch... Are you using threads by any chance? If, for instance, your calls to rand01 are done in a new thread, that new thread will have a *default* state of Mt19937. -Steve Good question, Steve, but I do not intentionally start any threads. Below is the machinery that interprets a for-loop. Do you see anything that would enclose a previous state of the RNG? ```d specialForms["for"] = function ExprInContext( ExprInContext eINc ){ // Execute a `for` loop, Default is to increment up by one // 1. Parse loop args Atom*[] loopArgs = flatten_atom_list( second( eINc.expr ) ); // Fetch args string iVarName = loopArgs[0].str; //Get the counter var name boolincrByOne = (loopArgs.length == 3); double loBound = 0.0; double hiBound = 0.0; double incr = 1.0; double i /*---*/ = 0.0; Atom* loopProg = third( eINc.expr ); // WARNING: TYPE NOT CHECKED Atom* rtnExpr = null; Env*nuEnv = null; ExprInContext runBlock; // Case: Default loop increments by 1.0 if( incrByOne ){ loBound = loopArgs[1].num; hiBound = loopArgs[2].num; // Case: User-specified increment }else if(loopArgs.length == 4){ loBound = loopArgs[1].num; incr= loopArgs[2].num; hiBound = loopArgs[3].num; // Else: There is a syntax error }else return ExprInContext( new Atom( F_Error.SYNTAX, loopArgs.length.to!string ~ " was an incorrect number of loop args. Expected 3 or 4." ), eINc.context, "`for` got an unexpected number of args" ); // 2. Create a new nested context, bind the counter var i = loBound; nuEnv = new Env(); nuEnv.parent = eINc.context; bind_atom( nuEnv, iVarName, new Atom( loBound ) ); runBlock = ExprInContext( loopProg, nuEnv, "loop body" ); // 3. LOOP: while( i <= hiBound ){ // run block in nested context rtnExpr = block_meaning( runBlock ).expr; i += incr; // increment // Store new counter value so that loop body can access it bind_atom( nuEnv, iVarName, new Atom( i ) ); } return ExprInContext( rtnExpr, eINc.context, "loop result" ); }; ```
Re: Preventing nested struct destructor accessing stack frame
On Tuesday, 20 December 2022 at 06:31:09 UTC, ag0aep6g wrote: On 16.12.22 14:07, Nick Treleaven wrote: This seems to work: ~this() @trusted { if ( > cast(void*)1024) i++; } It would be better if there was a struct property to get the context pointer though. A quick test suggests that the context pointer is the last item in `tupleof`. So this might do the trick: ~this() { if (this.tupleof[$ - 1] !is null) i++; } I don't know if it's guaranteed to work though. Might be an implementation detail. Great, thanks. The struct tupleof docs just link to the class tupleof docs, which say: The order of the fields in the tuple matches the order in which the fields are declared. So I think for a struct the context pointer has to come after any fields.