Thread overview
built-in int[] opSliceOpAssign throws?
Sep 12, 2012
monarch_dodra
Sep 12, 2012
Namespace
Sep 12, 2012
monarch_dodra
Sep 12, 2012
Jonathan M Davis
September 12, 2012
--------
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?
September 12, 2012
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);
}
September 12, 2012
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)?
September 12, 2012
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