From: Michael P F. <mic...@ug...> - 2012-03-04 15:10:18
|
Hi Chapel Developers - I've compared Chapel's argument intents with 3 other languages and I'm proposing something I think makes them more reasonable. I'm hoping that my proposal is not very different from the original goals of Chapel intents or current directions. We discussed this before in May 2011 "intents, record assignment". After that, I unfortunately remained confused about what 'inout' means (which actually caused some bugs in my code..) So, I went ahead and looked at C#, D, and Pascal, which all have argument intents. What are the semantics? First, my sources: C# spec sec 7.4.1 http://msdn.microsoft.com/en-us/library/aa691335(v=vs.71).aspx sec 10.5.1 http://msdn.microsoft.com/en-us/library/aa645761(v=vs.71).aspx D spec "Function Parameters" http://www.digitalmars.com/d/1.0/function.html Free Pascal reference sec 14.4 http://www.freepascal.org/docs-html/ref/refse77.html Here's a little table summarizing (you might have to un-line-wrap): | default | by-ref | out | note C# | by-value mutable | ref | out, must set in func | ref/out in call ie y=f(ref x); D | by-value mutable | inout | out, default initialized | also in==default, lazy Pascal | by-value mutable | var | out, should set in func | also const, out is extension Note that D's 'inout' does NOT mean the same as Chapel's - in D it just means "Pass by reference". My understanding of the current state in Chapel: Chapel | ref or val | - | out | inout is sortof by ref (ref arrays, ref sync, otherwise mutable val) I understand that 'const', 'const in', 'const ref', and 'ref' intents have been proposed. Note that: - All 3 of these languages have a simple default that applies to everything (although that's in the language designer's mind - ie class instances are actually pointers that are passed by value, vs 'objects' that are passed by reference). - NONE of them have Chapel's weird copy-in copy-out semantics, and D has what I thought Chapel had using the SAME NAME! Rather unfortunate. I personally think that we should have: Chapel | const (val/ref) | ref | out | in for mutable by-value Here const (val/ref) means that the default is to not allow a function to change its arguments unless they have an intent. That way, the most natural thing in terms of implementation and performance will simply apply (arrays get passed by pointer, integers get passed by value, etc). The compiler should give an error if an argument with default intent is modified. We'd probably want to note that class instances are reference types and so really we pass a pointer to a class instance in any case (and that pointer is passed by value). The real reason for passing const val/ref by default is that since array assignment copies the contents of the array, arrays are value types not reference types, and so the current implementation has an inconsistency (arrays are value types that are passed by reference). At the same time, passing arrays by value by default is almost certainly a terrible idea for performance. Likewise, tuples and records are value types that will perform better if generally passed by reference. Since most uses of single/sync variables will change their value, passing them const(val/ref) would mean the same as reading the sync variable in the caller and then passing the read contents. I'd give an error in that case. In other words, you wouldn't be able to meaningfully have a sync/single argument in a function unless you used a pass-by-reference intent. Also, an aside, I think it's very important to be aware of which arguments to a function are getting set; thus I'd even favor the C# syntax where you have to repeat an out or ref intent in a call, but that's less of a big deal to me. I also think that our choice here has implications for generic functions. Suppose I am writing a generic function taking one argument. I have one of 3 situations: 1) I want to have a mutable copy of the argument (I'm changing it, but changes should be local) 2) I want to have a mutable reference to the argument (I'm changing it, changes happen in caller) 3) I don't ever need to change the argument In the current situation, I don't know if I'm getting by-value or by-reference in the default, so if I want one function for all data types and I need to tell the compiler to do 1,2, or 3, I have to use 'in' intent to get #1, can't get #2 (although 'ref' is proposed and inout sortof does the right thing), and there's also no way to get #3, but perhaps I could do it with a proposed 'const' intent. Under my proposal, I'd use in to get #1, ref to get #2, and the default always gives #3. I don't really care if the pass-by-reference intent is called ref or var or inout; those all seem reasonable to me, but I think 'by reference' is more likely what a programmer wanted than the current copy-in/copy-out semantics, even if the intent is called inout. Cheers, -michael |