www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - built-in int[] opSliceOpAssign throws?

reply "monarch_dodra" <monarchdodra gmail.com> writes:
--------
nothrow void foo1(int[] a)
{
     foreach(i; 0..10)
     {
         a[i]  = 5;
         a[i] += 5;
     }
}

nothrow void foo2(int[] a) //10
{
     a[0..10]  = 5;  //12
     a[0..10] += 5;  //13
}
--------
main.d(13): Error: _arrayExpSliceAddass_i is not nothrow
main.d(10): Error: function main.foo2 'foo2' is nothrow yet may 
throw
--------

Making an out of range call in foo2 (after removing nothrow) 
throws an _ERROR_ in both line 12 and 13 (if commenting 12):
core.exception.RangeError main(12): Range violation
core.exception.RangeError main(13): Range violation
Is there any situation where it actually *could* throw an 
exception?

This is a bug? I did not find any entries in Bug report. Should I 
report this?

I need to make the above call in a nothrow function. Is there any 
way to make it work, without any run-time cost?
Sep 12 2012
next sibling parent "Namespace" <rswhite4 googlemail.com> writes:
You are right, slice isn't nothrow, this should may be fixed.
But if you don't assign your dynamic array first, you have a 
problem: you cannot put elements in a empty dynamic array with 
arr[i] = val;, you have to use arr ~= val;

This code works:

import std.stdio;

nothrow void foo1(ref int[] a)
{
     foreach(i; 0..10)
     {
         a ~= 5;
         a[i] += 5;
     }
}

void foo2(ref int[] a) //10
{
     a[]  = 5;  //12, no explicit slice, so the whole array is 
assigned with 5
     a[] += 7;  //13
}

void main() {
	int[] a;
	
	foo1(a);
	foo2(a);
	
	writeln(a);
}
Sep 12 2012
prev sibling next sibling parent "monarch_dodra" <monarchdodra gmail.com> writes:
On Wednesday, 12 September 2012 at 09:50:09 UTC, Namespace wrote:
 You are right, slice isn't nothrow, this should may be fixed.
 But if you don't assign your dynamic array first, you have a 
 problem: you cannot put elements in a empty dynamic array with 
 arr[i] = val;, you have to use arr ~= val;

 This code works:

 import std.stdio;

 nothrow void foo1(ref int[] a)
 {
     foreach(i; 0..10)
     {
         a ~= 5;
         a[i] += 5;
     }
 }

 void foo2(ref int[] a) //10
 {
     a[]  = 5;  //12, no explicit slice, so the whole array is 
 assigned with 5
     a[] += 7;  //13
 }

 void main() {
 	int[] a;
 	
 	foo1(a);
 	foo2(a);
 	
 	writeln(a);
 }

I think I foun out what is going on: It is a problem with overlap. According to specs, overlapping arrays are illegal: -------- void main() { int[10] b; b[] = 5; b[0..6] += b[4..10]; //6 b[0..6] = b[4..10]; //7 } -------- Here, Line 7 will produce an "object.Exception src\rt\arraycat.d(40): overlapping array copy". However, line 6 will produce nothing. Toying with it shows that it produces *unspecified* behavior. So rephrasing my question in 2 questions: 1) Shouldn't "b[0..6] += b[4..10]" throw "something"? 2) Shouldn't the thrown object be an Error (and not an Exception)?
Sep 12 2012
prev sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Wednesday, September 12, 2012 11:20:54 monarch_dodra wrote:
 This is a bug? I did not find any entries in Bug report. Should I
 report this?
 
 I need to make the above call in a nothrow function. Is there any
 way to make it work, without any run-time cost?

I believe that dup and idup have the same problem, and it definitely needs to be fixed. Regardless, pretty much the only sane way to call a function that throws in a nothrow function is to put a try-catch around it. try func(); catch(Exception e) assert(0, "func threw. That's supposed to be impossible."); But if you do that, you'd better be sure that it really _can't_ throw (if it can, then you need to actually handle the exception rather than asserting 0). - Jonathan M Davis
Sep 12 2012