www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - safe quiz

reply Michel Fortin <michel.fortin michelf.com> writes:
I've encountered the two following situations when playing with  safe 
and delegate literals, and I had to label more code as  trusted than I 
expected.

Here is some code:

	 safe void test(void function(int) doX, int i) {
		doX(i);
	}

	void main() {
		test((int i) { writeln(i); }, 1);
	}

Note that doSomething and main are not safe. Should that compile? 
Currently it doesn't with an error on the "doX(i);" line saying doX 
isn't  safe. (The compiler won't let you label the argument  safe 
either.) I think it should compile because it's main that should be 
held responsible for the code it gives to test, and since main isn't a 
safe function it should be allowed to pass something unsafe, even to a 
safe function.

Now let's do the same using a template:

	 safe void test(alias doX)(int i) {
		doX(i);
	}

	void main() {
		test!((int i) { writeln(i); })(1);
	}

Same here, except that instead of a function pointer we have a 
template. Should that compile? Basically, it's the same situation as 
above, and it doesn't compile either.

Which makes me think that obviously the same thing will happen with 
string mixins:

	 safe void test(string doX)(int i) {
		mixin(doX~";");
	}

	void main() {
		test!("writeln(i)")(1);
	}

Here, if writeln wasn't safe (and it currently isn't, that should be 
fixed in Phobos) there is no way this can compile. This is going to be 
pretty annoying if std.algorithm ever become  safe.

I'm not sure what should happen in the template case.


-- 
Michel Fortin
michel.fortin michelf.com
http://michelf.com/
Dec 30 2009
parent reply Walter Bright <newshound1 digitalmars.com> writes:
Michel Fortin wrote:
 Here, if writeln wasn't safe (and it currently isn't, that should be 
 fixed in Phobos) there is no way this can compile. This is going to be 
 pretty annoying if std.algorithm ever become  safe.

Nobody has gone through Phobos yet and labeled things appropriately. This, of course, needs to be done.
Dec 30 2009
parent reply Michel Fortin <michel.fortin michelf.com> writes:
On 2009-12-30 15:10:31 -0500, Walter Bright <newshound1 digitalmars.com> said:

 Michel Fortin wrote:
 Here, if writeln wasn't safe (and it currently isn't, that should be 
 fixed in Phobos) there is no way this can compile. This is going to be 
 pretty annoying if std.algorithm ever become  safe.

Nobody has gone through Phobos yet and labeled things appropriately. This, of course, needs to be done.

I know. But that wasn't really the point of that whole post. The point is that it's difficult to pass callable arguments to a safe function or function template. Labeling most function templates as safe in std.algorithm is going to break code that uses those algorithms. You'll see when you (or someone else) attempts it, just like I saw when I added safe to my code. -- Michel Fortin michel.fortin michelf.com http://michelf.com/
Dec 30 2009
parent reply Walter Bright <newshound1 digitalmars.com> writes:
Michel Fortin wrote:
 I know. But that wasn't really the point of that whole post. The point 
 is that it's difficult to pass callable arguments to a  safe function or 
 function template.
 
 Labeling most function templates as  safe in std.algorithm is going to 
 break code that uses those algorithms. You'll see when you (or someone 
 else) attempts it, just like I saw when I added  safe to my code.

I think that shows the type system is working. If a safe function can call a not safe delegate, then the type system has failed.
Dec 30 2009
parent reply Michel Fortin <michel.fortin michelf.com> writes:
On 2009-12-30 20:20:30 -0500, Walter Bright <newshound1 digitalmars.com> said:

 I think that shows the type system is working.

I think it shows that the type system is too strict and easily gets in the way.
 If a  safe function can call a not safe delegate, then the type system 
 has failed.

A safe function is only safe when given safe arguments. If a system function calls a safe function by giving it a garbage pointer, that safe function is able to corrupt anything. The same should apply for callable arguments (function pointers and delegates): a system function should be able to give a system delegate to a safe function, and that safe function should be able to call it. It's the caller that should be held responsible for giving an unsafe argument, and if the caller function is safe it shouldn't be allowed to pass an unsafe function as an argument. Here is a pathetic example of something that does not work currently: struct R { safe int opApply(int delegate(ref int) z) { int i = 1; return z(i); // Error: safe function 'opApply' cannot call system delegate 'z' } } system void someSystemFunction() { R r; foreach (i; r) { writeln(i); } } Should I have to write the opApply twice so it can work with both system and safe functions? I sure hope not. Even then, this does not compile either: safe void someSafeFunction() { R r; foreach (i; r) { writeln(i); } // Error: function untitled.R.opApply (int delegate(ref int) z) is not callable using argument types (int delegate(ref int __applyArg0)) } -- Michel Fortin michel.fortin michelf.com http://michelf.com/
Dec 30 2009
next sibling parent Michel Fortin <michel.fortin michelf.com> writes:
On 2009-12-30 23:41:54 -0500, Michel Fortin <michel.fortin michelf.com> said:

 Here is a pathetic example of something that does not work currently:
 
 struct R {
 	 safe int opApply(int delegate(ref int) z) {
 		int i = 1;
 		return z(i); // Error: safe function 'opApply' cannot call system 
 delegate 'z'
 	}
 }
 
  system
 void someSystemFunction() {
 	R r;
 	foreach (i; r) { writeln(i); }
 }
 
 Should I have to write the opApply twice so it can work with both 
 system and safe functions? I sure hope not. Even then, this does not 
 compile either:

I should add that I can write this to move the error somewhere else which is more illustrative of my point by tagging the argument as a safe delegate: struct R { safe int opApply(int delegate(ref int) safe z) { int i = 1; return z(i); } } system void someSystemFunction() { R r; foreach (i; r) { writeln(i); } // Error: function untitled.R.opApply (int delegate(ref int) z) is not callable using argument types (int delegate(ref int)) } This version of opApply gives no error if the caller is safe: safe void someSafeFunction() { R r; foreach (i; r) { writeln(i); } } (Except about writeln not being safe, but that's not a language issue.) -- Michel Fortin michel.fortin michelf.com http://michelf.com/
Dec 30 2009
prev sibling parent Walter Bright <newshound1 digitalmars.com> writes:
Michel Fortin wrote:
 On 2009-12-30 20:20:30 -0500, Walter Bright <newshound1 digitalmars.com> 
 said:
 
 I think that shows the type system is working.

I think it shows that the type system is too strict and easily gets in the way.

I think we can work to address those problems while keeping it strict. C++ const is an example of a not strict system which offers (as a consequence) no useful guarantees at all.
 If a  safe function can call a not safe delegate, then the type system 
 has failed.

A safe function is only safe when given safe arguments. If a system function calls a safe function by giving it a garbage pointer, that safe function is able to corrupt anything.

That's correct.
 The same should apply for callable arguments (function pointers and 
 delegates): a system function should be able to give a system delegate 
 to a safe function, and that safe function should be able to call it. 
 It's the caller that should be held responsible for giving an unsafe 
 argument, and if the caller function is safe it shouldn't be allowed to 
 pass an unsafe function as an argument.

I'll have to think about that one. I'm not sure I agree. But I'm glad you're bringing it up, it's important. I hadn't thought about this issue before.
 Here is a pathetic example of something that does not work currently:
 
 struct R {
      safe int opApply(int delegate(ref int) z) {
         int i = 1;
         return z(i); // Error: safe function 'opApply' cannot call 
 system delegate 'z'
     }
 }
 
  system
 void someSystemFunction() {
     R r;
     foreach (i; r) { writeln(i); }
 }
 
 Should I have to write the opApply twice so it can work with both system 
 and safe functions? I sure hope not. Even then, this does not compile 
 either:
 
  safe
 void someSafeFunction() {
     R r;
     foreach (i; r) { writeln(i); } // Error: function untitled.R.opApply 
 (int delegate(ref int) z) is not callable using argument types (int 
 delegate(ref int __applyArg0))
 }

There is certainly a problem here in that when the compiler creates the delegate to send to opApply, it doesn't tag it appropriately (or at all). These kinds of issues are to be expected with a new feature like safe, a couple of iterations will be necessary to straighten them out.
Dec 30 2009