The key point of this follow-up email is: we are looking for user input 
on how sync and single variables should work when passing them as 
arguments to functions with generic formals.

For 1.10, write() et al. on sync/single will generate a compiler error. 
We made this choice to raise community awareness and to avoid users 
getting surprising behavior from whatever other option we might have 
implemented.

min()/max() on sync/single/atomic will generate a compiler error, too. 
We will stick with this unless we hear strong arguments/proposals to the 
contrary.


In both the above cases, to perform the desired operation on a 
sync/single, you will need to invoke readFE()/readFF()/readXX() etc. 
explicitly, then pass the result to write()/min() etc. For example:

   var mySync$: sync int;
   var mySingle$: single real;
   ... start computing the above ...

   //Currently the following would generate compiler errors like:
   //  "IO.chpl:1691: error: sync/single variables cannot currently be 
written"
   //Run chpl --print-callstack-on-error to determine the source location.
   //
   // writeln("mySync$ = ", mySync$);
   // writeln("mySingle$ = ", mySingle$);

   //Specify the desired access explicitly.
   // E.g. write a pair of (is it full?, the value), non-atomically:
   writeln("mySync$ = ", (mySync$.isFull, mySync$.readXX()));
   // or wait until the variable is full:
   writeln("mySingle$ = ", mySingle$.readFF());


The above solution is not perfect because:

* If you have a record/class with a sync/single field, you will need to 
provide your own writeThis() method to enable write() on that 
record/class to compile. Without it the compiler provides a default 
implementation that invokes writeThis on each field. The latter 
currently generates a compiler error for sync/single fields.

For example:

   record RecordWithSync {
     var regularField: int;
     var syncField$: sync real;
     proc writeThis(x: Writer) {
       x.write("(", regularField, ", ", syncField$.readXX(), ")");
     }
   }

   var r: RecordWithSync;
   // This would generate a compiler error without writeThis() above.
   // Since we used readXX() there, this will never block.
   writeln(r);

* It is not symmetric with reading sync/single variables, for which it 
seems natural to wait until such a variable is empty and leave it full. 
Disclaimer: currently read() does not work on sync/single; this will not 
be fixed for 1.10.


Some of the questions we'd like input on are:

* What should write() do on a sync/single? Examples:

  - Not allowed (it's the current implementation).

  - "Consume" the full/empty state, i.e. implicitly do
    sync.readFE() or single.readFF().

  - Wait for, but not consume, the full state, i.e.
    implicitly do readFF() for sync and single.

  - Do not wait for the full state - print whether it's full.
    Example 1: "5.5" (when full), "<empty>" (when empty).
    Example 2: "f:5.5" (when full), "e:5.5" (when empty).

  - Others?

* What should write() do on a class/record containing a sync/single 
field, without user-defined writeThis or readWriteThis? Examples:

  - Do write() on the sync/single field, behaving according to the 
choice in the previous bullet.

  - Do something special, e.g. never "consume" the full/empty state of 
each field, like the last option in the previuos bullet.

  - Others?

* What should read() do on a sync/single? E.g. should it wait for the 
variable to become empty before storing a value into it? Or should it 
read in and set the variable's full/empty bit, besides reading the value?


There is more discussion in the commit message for the #420 merge, see:

   https://github.com/chapel-lang/chapel/commit/6c2e3a6

For example, it shows a new deadlock that our earlier implementation 
could result in, when a thread locked the channel before locking the 
sync variable.


Vass


On 09/16/14 09:02, Brad Chamberlain wrote:
> Hi all --
>
> As you may have seen/heard on github, Vass is working on a bug fix for the 
> long-term problem of passing sync/single to generic arguments:  Previously, 
> such cases were unwrapped and treated as reads of the actual argument, 
> passing in the underlying value with no full/empty state.  Thus, in:
>
> proc foo(x) {
>    ...
> }
>
> var mySyncVar$: sync int;
>
> foo(mySyncVar$);
>
> foo() would be interpreted as taking an int and the foo(mySyncVar$) would be 
> interpreted as foo(mySyncVar$.readFE()).  This has seemed inconsistent to 
> most of us for some time now, the original rationale for it didn't seem to 
> hold up as the language has matured, and it is something I attempted to fix a 
> year ago without success.  Vass has been more successful this month 
> (motivated by his work to get is*Type()-style queries working correctly for 
> all types).
>
> One place where this has impact is in the implementation of write/writeln for 
> sync/single, which were previously treated as a blocking read of the value 
> and passing the value to the corresponding write/writeln for its base type.  
> It has always seemed unfortunate/surprising to me (and to users, I believe) 
> to have such cases consume the full/empty state, and has led to buggy 
> programs, so what I've proposed we do for this release is to reinterpret 
> write/writeln as an inspection of the sync/single variable's full state, 
> writing:
>
> "<empty>", if the variable is empty
> its value, if the variable is full
>
> The rationale for this is that when you're writing something, I believe 
> you're typically wanting to inspect its logical state, not treat it as a 
> consumption of the value.  And that if someone wants the previous behavior, 
> they would call their own readFE/readFF at the callsite, passing the base 
> value on to the write/writeln call.  I think that this is a nice change and 
> improvement, but it's clearly a significant change so I wanted other 
> developers to be able to protest if they thought it was clearly wrong -- 
> particularly if they had a better proposal.  Or if it seems like too 
> big/scary a change to make so close to the release.
>
> Similarly, and less significantly, min()/max() are defined generically and as 
> a result, used to perform a readFE/readFF of a sync/single argument at the 
> callsite and then just operate on the base value.  In the new "pass the 
> sync/single by ref" interpretation, the generic implementations don't work 
> because they trip over the full/empty state.  Our proposal here is to not 
> support min()/max() on synchronized types, requiring users to do the 
> readFE/readFF at the callsite if they want to perform min()/max() on the 
> value being wrapped by the sync/single.  Thus, in Vass's patch, passing 
> min()/max() a sync or single (or atomic) results in a compiler error 
> explaining that those routines are not supported for said types.
>
> I think this semantic fix is long overdue and that the ensuing changes are 
> nice steps forward as well.  Moreover, I think that the fix makes it worth 
> taking the changes even at this late date in the 1.10 release cycle.  But if 
> there's a strong feeling that we should hold off until after the 1.10 branch 
> is cut, I'd like to hear that.
>
> Thanks,
> -Brad


------------------------------------------------------------------------------
Slashdot TV.  Video for Nerds.  Stuff that Matters.
http://pubads.g.doubleclick.net/gampad/clk?id=160591471&iu=/4140/ostg.clktrk
_______________________________________________
Chapel-developers mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/chapel-developers

Reply via email to