October 10, 2002 Re: passing arrays as "in" parameter with suprising results | ||||
---|---|---|---|---|
| ||||
Posted in reply to Walter | So how do you think you can pass a constant array to a function? The function could modify the constant and the language has no way of preventing it or even warning you about it. It might prevent you from calling any function with the constant as an inout or out parameter. But if the contents of 'in' arrays are mutable this still leaves gaping safety holes. Sean "Walter" <walter@digitalmars.com> wrote in message news:ao47q4$1s5j$1@digitaldaemon.com... > > "Sean L. Palmer" <seanpalmer@directvinternet.com> wrote in message news:ao37ep$ine$1@digitaldaemon.com... > > They affect the speed with which you can test if something is null or not. > > You can't test the length for null first because to do so you must dereference the pointer, which if null is an error. So to be safe, first > > you must test the pointer then the length for 0, and only then do you have > > enough information to know if you should start the loop. > > This is incorrect. A reference to an array is a pair, one is the length and > the other is the pointer. The length can therefore be tested without dereferencing any pointer. You are right. > > I really think in parameters should be thoroughly immutable to the point > of > > not being able to be passed as mutable array parameters themselves (to do > so > > you must make a copy). This feature limits references to array entries explicitly requested and thus can be tracked and contained by the > compiler. > > Otherwise there's no way you can easily enforce a contract that clients > not > > misuse your data. The contract has to be visible in the language somehow, > > either implicit or explicit. Then the callee has to guarantee not to > write > > to its parms in order to be able to take parms which are constant or thru > > refs to read-only data. Otherwise we'll just end up with an uncontrolled > > mess. > > I think what you're arguing for is something like C++'s const& type modifier. > > > If you want to ensure that your client does not abuse your data, typecast > > your data to be const before passing it to them. If it doesn't have the contract that says "I won't abuse your data" then the caller has to proactively make a copy of the constant and send that in just in case the > > routine decides to mess around with the data you pass it. No other way to > > be safe. > > > > The other way, (C++'s way) at least you can get a reasonable guarantee > which > > is usually enforced pretty well by the compiler, that something won't > misuse > > your data, without having to resort to expensive runtime data duplication. > > > > Does that qualify as an optimization, or not? It is, but only when the > data > > is in fact unwritable and you care enough about it to make that copy. > Which > > isn't all that often in practice. All nuts and bolts and hoses and > adaptor > > sockets. Usually you hook things up right (but that damn 5% when you get > it > > wrong and have to figure out what went wrong!) That's when a tool like const becomes handy. It lets you track down overwrite bugs. Hell it lets > > you prevent them. > > I understand why you want const parameters and I know you rely on it to find > bugs, but I am less convinced of its payback/cost. > > > |
October 10, 2002 Array ownership - new contract type | ||||
---|---|---|---|---|
| ||||
Posted in reply to Sean L. Palmer | As far as I understand the conversation "Re: passing arrays as "in" parameter with suprising results," Sean makes good observations. To me 'in' means that data is immutable by the callee. If the usage is 'inout', then it should be specified as such. Comparisons with C++ const qualifiers are probably out of place. All we need is clarity on the meanings of 'in', 'out', and 'inout' as D contracts. Whatever 'in' means, it should mean for *all* data types, including arrays. Possibly another type of contract is not yet covered by D. In numeric work one designs classes that know how to circulate array pointers from hand to hand with certain conventions for data ownership. In D, these conventions should be contracts. So a function might create an array, then pass it to another function with the expectation that the callee will assume ownership. Implicit with ownership is the ability to change or dispose of data. In such cases I don't know that any type of D contract works. The contract is not 'inout' because the data never comes back to the caller, and it's not 'in' because the data is mutable in the callee. Maybe D needs a new contract qualifier, 'transfer', to signal this type of contract. Mark |
October 10, 2002 Re: Array ownership - new contract type | ||||
---|---|---|---|---|
| ||||
Posted in reply to Mark Evans | Sandor wrote:
>"In" means "pass a copy of the value to the function".
>For "primitive types" (Java jargon), this means copy the value, for objects,
>it means copy the reference.
>For arrays it means some mystic in-between.
The "mystic in-between" shows that D contract semantics are not yet well-defined. Implementation details are unimportant until contract definitions are clear.
'In' should mean that the callee has access to the data, but cannot change it. Whether access comes from copied data, pointers, or references is irrelevant to the contract. Access mechanisms are mere implementation details.
Contracts are absent in C/C++ so they merit discussion. Attention to date has instead focused on mappings from implementations to contracts. This focus is misguided precisely because contracts do not exist in C/C++. What we'll end up with are D contracts isomorphic to C++ constructs, rendering D contracts redundant. D wants to offer something new that C++ never did.
One contract may employ many implementations to cover different data types. The commonality between them should be to yield the same contract semantics. It is OK that 'in' employs different access mechanisms for different data types; it is not OK that 'in' means different contracts for different data types.
Mark
|
October 11, 2002 Re: Array ownership - new contract type | ||||
---|---|---|---|---|
| ||||
Posted in reply to Mark Evans | An example of the 'transfer' contract at work might be ROME, "ROME was designed to manage high speed data streams within a multimedia environment....To ensure a high throughput with minimal overhead ROME provides a zero copy architecture where pointer references to data are passed around instead of data being copied. The goal of this approach is to maximize the utilization of a given hardware configuration." http://rome.sourceforge.net/ |
October 11, 2002 Re: Array ownership - new contract type | ||||
---|---|---|---|---|
| ||||
Posted in reply to Mark Evans | donate or gift perhaps. Or send. Maybe send is the default. And would it send a copy, or the original? void DestroyForever(gift object theobj) { delete theobj; } class Keeper { public void Keep(gift theobj) { assert(theobj == null); myobj = theobj; } public gift object GiveBack() { assert(object); object temp = myobj; myobj = null; return temp; } ~this() { delete myobj; } private object myobj; } But with GC you don't exactly need ownership to be controlled or even monitored. I think it would be more efficient to monitor it, myself. Sean "Mark Evans" <Mark_member@pathlink.com> wrote in message news:ao4mqc$2bgj$1@digitaldaemon.com... > As far as I understand the conversation "Re: passing arrays as "in" parameter > with suprising results," Sean makes good observations. To me 'in' means that > data is immutable by the callee. If the usage is 'inout', then it should be > specified as such. > > Comparisons with C++ const qualifiers are probably out of place. All we need is > clarity on the meanings of 'in', 'out', and 'inout' as D contracts. Whatever > 'in' means, it should mean for *all* data types, including arrays. > > Possibly another type of contract is not yet covered by D. In numeric work one > designs classes that know how to circulate array pointers from hand to hand with > certain conventions for data ownership. In D, these conventions should be contracts. > > So a function might create an array, then pass it to another function with the > expectation that the callee will assume ownership. Implicit with ownership is > the ability to change or dispose of data. > > In such cases I don't know that any type of D contract works. The contract is > not 'inout' because the data never comes back to the caller, and it's not 'in' > because the data is mutable in the callee. Maybe D needs a new contract qualifier, 'transfer', to signal this type of contract. > > Mark > > |
October 11, 2002 Re: Array ownership - new contract type | ||||
---|---|---|---|---|
| ||||
Posted in reply to Sean L. Palmer | Sean L. Palmer wrote:
> And would it send a copy, or the original?
The original. Copying violates the definition of the contract, which says that a blob (array/class instance/struct) is being transferred from one owner to another.
Think of an array as an input to some processing chain. Various objects get a hold of it and process it. Each hands it off to the next processing object in the chain. A transfer contract would be ideal for such applications.
Usually there are no dedicated give/keep functions but simply conventions on particular functions. "If you call me with an array, I get to keep it, and you no longer own it." This is exactly the kind of convention that D seeks to embody in its contracts. In C++ the best you can do is document the convention in the code comments and hope that users follow it properly.
Mark
|
October 12, 2002 Re: Array ownership - new contract type | ||||
---|---|---|---|---|
| ||||
Posted in reply to Mark Evans | "Mark Evans" <Mark_member@pathlink.com> wrote in message news:ao4mqc$2bgj$1@digitaldaemon.com... > As far as I understand the conversation "Re: passing arrays as "in" parameter > with suprising results," Sean makes good observations. To me 'in' means that > data is immutable by the callee. If the usage is 'inout', then it should be > specified as such. Depends on how you think about it. In D, 'in' means the parameter gets a copy of the value, and so cannot change the original. Since arrays are passed by reference, indeed, the caller's *reference* cannot change, but what it refers to can. Think about it like passing a reference to a class object. You can't change the caller's reference, but you can certainly change the data in the class object. > Comparisons with C++ const qualifiers are probably out of place. All we need is > clarity on the meanings of 'in', 'out', and 'inout' as D contracts. Whatever > 'in' means, it should mean for *all* data types, including arrays. There's no way to avoid dealing with the different semantics between by reference and by value. Arrays and classes are always by reference. Structs and scalars are always by value. 'out' and 'inout' add another reference layer on top of that. > Possibly another type of contract is not yet covered by D. In numeric work one > designs classes that know how to circulate array pointers from hand to hand with > certain conventions for data ownership. In D, these conventions should be contracts. > > So a function might create an array, then pass it to another function with the > expectation that the callee will assume ownership. Implicit with ownership is > the ability to change or dispose of data. > > In such cases I don't know that any type of D contract works. The contract is > not 'inout' because the data never comes back to the caller, and it's not 'in' > because the data is mutable in the callee. Maybe D needs a new contract qualifier, 'transfer', to signal this type of contract. You raise an excellent point. The quality "who owns this value" is a major programming problem in C++ with memory management, as it is needed to decide who must and who cannot free the memory. D avoids that problem by using garbage collection, which means the programmer does not have to keep track of ownership. The way to deal with other kinds of ownership of data is to follow the "copy on write" rule. For example, a char[] strupr(in char[] s) function would simply return s if the array is already upper cased. If the array is not upper cased, then a copy of s is made, upper cased, and returned. I'm not sure how to make contracts for that, as it is a programming technique not a syntactical feature. |
October 12, 2002 Re: Array ownership - new contract type | ||||
---|---|---|---|---|
| ||||
Posted in reply to Walter |
>
> Depends on how you think about it. In D, 'in' means the parameter gets a copy of the value, and so cannot change the original. Since arrays are passed by reference, indeed, the caller's *reference* cannot change, but what it refers to can. Think about it like passing a reference to a class object. You can't change the caller's reference, but you can certainly change the data in the class object.
>
What is in the conceptual 'array' object intended to be ?
it would seem better if the conceptual 'array' *object* was { uint length; T
* data; }
as opposed to the current { T data[fixed]; }
IMHO : it would be nice to have a language defined by its semantics and not its implementation.
Mike.
|
October 12, 2002 Re: Array ownership - new contract type | ||||
---|---|---|---|---|
| ||||
Posted in reply to Walter | Walter wrote: >Depends on how you think about it. In D, 'in' means the parameter gets a copy of the value, and so cannot change the original. Since arrays are passed by reference, indeed, the caller's *reference* cannot change, but what it refers to can. Think about it like passing a reference to a class object. You can't change the caller's reference, but you can certainly change the data in the class object. I find this an exceptionally confusing way to define 'in' and not a very useful one. If this is how contracts work, then they are pretty useless, conceptually. >There's no way to avoid dealing with the different semantics between by reference and by value. Arrays and classes are always by reference. Structs and scalars are always by value. 'out' and 'inout' add another reference layer on top of that. I'm not proposing avoidance, just consistency. The compiler can use call-by-reference and still disallow data changes. You are saying that just by virtue of being a reference, the corresponding data is mutable, which I don't buy. (It may be the easiest thing to implement but that doesn't make it the best arrangement.) >You raise an excellent point. The quality "who owns this value" is a major >programming problem in C++ with memory management...D avoids that problem by >using garbage collection, which means the programmer does not have to >keep track of ownership. Garbage collection doesn't eliminate the problem. "Who owns the value" also determines who prevents the garbage collector from getting rid of it, who is allowed to process the data, as well as who is ultimately allowed to release it to the garbage collector. >The way to deal with other kinds of ownership of data is to follow the "copy on write" rule. There are many such conventions. The idea of D is to replace conventions with contracts. Or so I thought. Mike wrote: >IMHO : it would be nice to have a language defined by its semantics and not its implementation. Exactly the point I keep trying to make, Mark |
October 14, 2002 Re: Array ownership - new contract type | ||||
---|---|---|---|---|
| ||||
Posted in reply to Mark Evans | "Mark Evans" <Mark_member@pathlink.com> wrote in message news:aoa2uk$1v2k$1@digitaldaemon.com... > Walter wrote: > > >Depends on how you think about it. In D, 'in' means the parameter gets a copy of the value, and so cannot change the original. Since arrays are passed by reference, indeed, the caller's *reference* cannot change, but what it refers to can. Think about it like passing a reference to a class object. You can't change the caller's reference, but you can certainly change the data in the class object. > > I find this an exceptionally confusing way to define 'in' and not a very useful > one. If this is how contracts work, then they are pretty useless, conceptually. They are usefull. Thousands of Java developers can live with it. But IMHO they can be made better. Especially concerning passing arrays. > >There's no way to avoid dealing with the different semantics between by reference and by value. Arrays and classes are always by reference. Structs > >and scalars are always by value. 'out' and 'inout' add another reference layer on top of that. > > I'm not proposing avoidance, just consistency. The compiler can use call-by-reference and still disallow data changes. You are saying that just by > virtue of being a reference, the corresponding data is mutable, which I don't > buy. (It may be the easiest thing to implement but that doesn't make it the > best arrangement.) > > > Mike wrote: > >IMHO : it would be nice to have a language defined by its semantics and not > >its implementation. > > Exactly the point I keep trying to make, I also agree. I still think it would be usefull to make a detailed comparsion to C++ parameter passing semantics. 1 - Primitive types ------------------ 1.1 - pass by value in C++: void fn(int a); in D: void fn(in int a); 1.2 - pass by value, immutable in C++: void fn(const int a); in D: ABSENT 1.3 - pass by reference/address in C++: void fn(int &a); in D: void fn(out int a); / void fn(inout int a); 1.4 - pass by reference/address, immutable in C++: void fn(const int &a); in D: ABSENT This is not the same as 1.2, from the semantical view. I can provide example if needed. 1.5 - pass by copy/copyback in C++: ABSENT in D: ABSENT 2 - Objects ------------ 2.1 - pass by value in C++: void fn(Object a); in D: ABSENT 2.2 - pass by value, immutable in C++: void fn(const Object a); in D: ABSENT 2.3 - pass by reference/address in C++: void fn(Object &a); in D: void fn(in Object a); 2.4 - pass by reference/addess, immutable int C++: void fn(const Object &a); in D: ABSENT 2.5 - pass by copy/copyback in C++: ABSENT in D: ABSENT 2.6 - pass by reference/address of reference/address in C++: void fn(Object *&a); in D: void fn(out Object a); / void fn(inout Object a) 2.7 - pass by reference/address of reference/addess, immutable in C++: void fn(const Object *&a); in D: ABSENT 3 - Arrays ----------- 3.1 - pass by value of the items (copy) in C++: void fn(vector<int> a); in D: ABSENT 3.2 - pass by value of the items (copy), immutable in C++: void fn(const vector<int> a); in D: ABSENT 3.3 - pass by reference/addess to the items in C++: void fn(int *a, int len); in D: void fn(in int[] a); Neither of them is elegant. You cannot resize the array, but you can modify the items. 3.4 - pass by reference/address to the items, immutable items in C++: void fn(const int *a, int len); in D: ABSENT 3.5 - pass by copy/copyback in C++: ABSENT in D: ABSENT 3.6 - pass by reference/address of reference/address of the items in C++: void fn(vector<int> &a); in D: void fn(out int[] a) / void fn(inout int[] a) 2.7 - pass by reference/address of reference/addess of the items, immutable items in C++: void fn(vector<int> &a); in D: ABSENT Conclusion: - Neither language provides copy/copyback. - D provides pass-by-value semantics only for primitive types. - D does not provide immutable parameter semantics. - D extends, and separates the concept of pass-by-reference to "out" and "inout" parameters Sandor |
Copyright © 1999-2021 by the D Language Foundation