On Wednesday, 29 August 2012 at 04:54:31 UTC, Tommi wrote:
On Wednesday, 29 August 2012 at 03:17:39 UTC, Era Scarecrow
I think that's right; Otherwise ref wouldn't be allowed in @safe code (at all).

But couldn't the compiler disallow all unsafe ref use in @safe code, and allow all use of ref in @system and @trusted code?

So.... Ref can only then be used if it's heap allocated... That would be the only @safe way, but even that is ridden with timebombs.

 int[10] xyz;

 foreach(i; xyz) {
   //all's good, they are copies!
 }

 foreach(ref i; xyz) {
   // cannot use ref, (not even const ref) as it may be unsafe
 }

 //a ref function
 void func(ref int i);

 int *z = new int;
 func(z); //or is it *z? 'Might' be good
 func(xyz[0]); //Compile error, may be unsafe.

 class C {
   int cc;
 }

 struct S {
   int sc;
 }

 C cSomething = new C();
 S sSomething = S();
 S* sSomething2 = new S();

 func(cSomething.cc); //good, heap allocated enforced
 func(sSomething.sc); //error, may be unsafe!
func(sSomething2.sc); //pointer dereference; It bypasses protections since it probably is heap (but not guaranteed), so maybe this should fail too.

 sSomething2 = &sSomething;
func(sSomething2.sc); //back to a timebomb situation but the compiler can't verify it! only something from a class could be considered safe (maybe)



 Why is it unsafe? Let's assume we did this:

ref int unsafe; //global ref. Hey it's legal if ref is allowed as you want it!

 void func(ref int i) {
   unsafe = i;
 }

Now I ask you. If any of the 'unsafe' ones were used and then the scope ended that held that information and we use unsafe now, it can only be a time bomb: All of them stem from them being on the stack.

 void someFunc() {
   int stacked = 42;
   func(stacked);
 }

 someFunc();
 writeln(unsafe); //what will this print? Will it crash?

 //some scope. FOR loop? IF statement? who cares?
 {
   int local = 42;
func(&local); //assuming the pointer bypasses and gets dereferenced to get past the heap only compiler problems (pointers and classes only) limitations
   writeln(unsafe); //prints 42 as expected
 }

writeln(unsafe); //????? Scope ended. Now what? can't ensure local exists anymore as we reffed a stack


 class Reffed {
   ref int i;
 }

//some scope
 Reffed r = new Reffed();
 Reffed r2 = new Reffed();

 @trusted {
   int local;
r.i = local; //may or may not work normally, @trusted should force it
 }

 //Why not copy a reference from a class?
 //it should be good (heap only), right?
 r2.i = r.i;

 writeln(r.i); //?????
 writeln(r2.i); //?!?!


To make it 'safe' the only way to do it is ref can only be used on heap allocated data (or global fixed data). The current implementation as I see it anything referenced is safe because you can only reference something that currently exists (via function calls).

The other way to make it safe is to silently include a flag that specifies if it was stack allocated or not, but even that becomes more complicated and more of an issue.

Reply via email to