Re: Confusion about `Random`

2022-12-23 Thread H. S. Teoh via Digitalmars-d-learn
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

2022-12-23 Thread Steven Schveighoffer via Digitalmars-d-learn

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`

2022-12-23 Thread Steven Schveighoffer via Digitalmars-d-learn

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`

2022-12-23 Thread jwatson-CO-edu via Digitalmars-d-learn

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`

2022-12-23 Thread jwatson-CO-edu via Digitalmars-d-learn

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`

2022-12-23 Thread jwatson-CO-edu via Digitalmars-d-learn
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

2022-12-23 Thread Nick Treleaven via Digitalmars-d-learn

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.