www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Re: Function calls

reply Steven Schveighoffer <schveiguy yahoo.com> writes:
Andrei Alexandrescu Wrote:

 Michiel Helvensteijn wrote:
 Andrei Alexandrescu wrote:
 
 foreach (line; stdin.byLine()) { ... }

 vs.

 foreach (line; stdin.byLine) { ... }

 How do I choose?

-Steve


byLine() is a function. It changes the state of stdin. Calling it consecutively will in general result in different return values. If there were two guys: stdin.currentLine (property) and stdin.nextLine(), it would be a different story.


No no no. byLine returns a struct, it does not modify stdin. Operating on the struct modifies stdin, but that is outside the call to the property getter. Look at it this way (although this is not the only way to look at it), could byLine be a field inside stdin? It could. You could store a copy of what byLine returns inside stdin, and people could just access it.
 A property should act very much like a field. The advantages of properties
 are that they can be derived (not have a one-to-one relation with a storage
 location) or can do some clever caching/memoizing/logging.

I agree, but I'll also note that I got contradictory opinions from different supporters of property. So now it looks all the more like a judgment call, which is exactly what I was worried in the first place.

There are some cases that are judgement calls and some that are obvious. byLine is obvious. The difference is that the *author* is making the judgement call, not the *user*. The difference is important, because when a user complains that your property is doing things a property shouldn't, and then you realize the "property" in question isn't even a property at all, your only solution (with the non-attributed system) is to tell the user not to use it that way. There is no way to get him to stop, or to get other users to stop. You have lost control over the semantic meaning of your function, even though you defined it and documented it. And yes, this did actually happen to me.
 
 Omitting parentheses on an action just because you can is stupid. It
 actually makes the language less readable and less predictable. And all
 that for saving two keystrokes.

I found my code to be more readable and just as predictable with the current rule. And it's not about two keystrokes, it's about persistent and ubiquitous syntactic noise. Gosh, property does suck. I was afraid that'd be true.

This is your opinion when reading *your* code. It doesn't suck if you value being able to read code written by *others*. -Steve
Jan 28 2010
next sibling parent reply =?UTF-8?B?UGVsbGUgTcOlbnNzb24=?= <pelle.mansson gmail.com> writes:
On 01/29/2010 05:20 AM, Steven Schveighoffer wrote:
 Look at it this way (although this is not the only way to look at it), could
byLine be a field inside stdin?  It could.  You could store a copy of what
byLine returns inside stdin, and people could just access it.

byLine modifies stdin. If you do this: auto a = stdin.byLine; You consume a line off stdin.
 There are some cases that are judgement calls and some that are obvious. 
byLine is obvious.

Apparently not.
 The difference is that the *author* is making the judgement call, not the
*user*.  The difference is important, because when a user complains that your
property is doing things a property shouldn't, and then you realize the
"property" in question isn't even a property at all, your only solution (with
the non-attributed system) is to tell the user not to use it that way.  There
is no way to get him to stop, or to get other users to stop.  You have lost
control over the semantic meaning of your function, even though you defined it
and documented it.

 And yes, this did actually happen to me.

Sounds like a naming issue to me. :)
Jan 29 2010
next sibling parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Fri, 29 Jan 2010 06:16:15 -0500, Pelle Månsson  
<pelle.mansson gmail.com> wrote:

 On 01/29/2010 05:20 AM, Steven Schveighoffer wrote:
 Look at it this way (although this is not the only way to look at it),  
 could byLine be a field inside stdin?  It could.  You could store a  
 copy of what byLine returns inside stdin, and people could just access  
 it.

byLine modifies stdin. If you do this: auto a = stdin.byLine; You consume a line off stdin.

That's a deficiency in the design of byLine. It's a range that "primes" itself with a line of text. The fact that you can enter the line above and just throw away the data seems error prone to me. When would you ever use that "feature"? In practice, it doesn't matter, because the only purpose to fetch the byLine struct is to iterate data from stdin. The design could be fixed with a boolean isPrimed that is unset on the first call to front. But like I said, it doesn't matter in the long run, since nobody ever fetches byLine without using it. I find that the shoehorning of an input range onto a stream is always going to have this problem, so there's not much we can do about it. It doesn't change the concept that byLine is a property. I find streams much better suited to opApply, but I've already had that unsuccessful battle, and I don't want to have it again.
 There are some cases that are judgement calls and some that are  
 obvious.  byLine is obvious.

Apparently not.

I don't see why you think it's not a property. It fetches a range from stdin, there is no other purpose. If you think byLine's purpose is to throw away a line of text, I think first that you are now attaching unintended semantic meaning to it (exactly what properties are meant to prevent) and second, I'd consider it to be a poorly named function. I guess someone should complain that it's not called popLine(), because as a function, that's what it does.
 The difference is that the *author* is making the judgement call, not  
 the *user*.  The difference is important, because when a user complains  
 that your property is doing things a property shouldn't, and then you  
 realize the "property" in question isn't even a property at all, your  
 only solution (with the non-attributed system) is to tell the user not  
 to use it that way.  There is no way to get him to stop, or to get  
 other users to stop.  You have lost control over the semantic meaning  
 of your function, even though you defined it and documented it.

 And yes, this did actually happen to me.

Sounds like a naming issue to me. :)

You be the judge: http://www.dsource.org/projects/tango/ticket/1184 I find the resulting workaround very unsavory. -Steve
Jan 29 2010
parent reply =?UTF-8?B?UGVsbGUgTcOlbnNzb24=?= <pelle.mansson gmail.com> writes:
On 01/29/2010 02:01 PM, Steven Schveighoffer wrote:
 That's a deficiency in the design of byLine. It's a range that "primes"
 itself with a line of text. The fact that you can enter the line above
 and just throw away the data seems error prone to me. When would you
 ever use that "feature"? In practice, it doesn't matter, because the
 only purpose to fetch the byLine struct is to iterate data from stdin.

 The design could be fixed with a boolean isPrimed that is unset on the
 first call to front. But like I said, it doesn't matter in the long run,
 since nobody ever fetches byLine without using it.

 I find that the shoehorning of an input range onto a stream is always
 going to have this problem, so there's not much we can do about it. It
 doesn't change the concept that byLine is a property. I find streams
 much better suited to opApply, but I've already had that unsuccessful
 battle, and I don't want to have it again.

So byLine should be a property when implemented as a range, and a function when implemented as an opApply based loop? I feel that is a problem.
 You be the judge: http://www.dsource.org/projects/tango/ticket/1184

 I find the resulting workaround very unsavory.

 -Steve

That's the assignment syntax, which I do agree is weird. Sorry if I was unclear. This is what I thought property was for. It has, however, nothing to do with the omitting of the ().
Jan 29 2010
parent reply =?UTF-8?B?UGVsbGUgTcOlbnNzb24=?= <pelle.mansson gmail.com> writes:
On 01/29/2010 07:10 PM, Steven Schveighoffer wrote:
 Note in the anecdote above, both users would have
 been satisfied if you could *only* call empty without parentheses.

That's a good point. The writeln = 3; is also a good point. :) What I'm trying to defend is the ability to call non-property functions without the parens. I find this: array.stable_sort; file.detach; range.popFront; to look less noisy, clearer and just plain sexier than the respective versions with the parens.
Jan 29 2010
next sibling parent =?UTF-8?B?UGVsbGUgTcOlbnNzb24=?= <pelle.mansson gmail.com> writes:
On 01/29/2010 08:07 PM, Steven Schveighoffer wrote:
 On Fri, 29 Jan 2010 13:43:50 -0500, Pelle Månsson
 <pelle.mansson gmail.com> wrote:

 On 01/29/2010 07:10 PM, Steven Schveighoffer wrote:
 Note in the anecdote above, both users would have
 been satisfied if you could *only* call empty without parentheses.

That's a good point. The writeln = 3; is also a good point. :) What I'm trying to defend is the ability to call non-property functions without the parens. I find this: array.stable_sort; file.detach; range.popFront; to look less noisy, clearer and just plain sexier than the respective versions with the parens.

You've cited three functions where the function names cannot be misinterpreted as properties. This is not the case for all function names. If you wish to have a way to specify a function can be called either way, then I think you also need a way to specify that a function can only be called with parentheses. I don't disagree that the above is unambiguous, but there are examples where it is ambiguous. f.read; does this mean read f, or is it an accidental noop fetching a property indicating f is read? Requiring parentheses also allows you to force meanings where they would otherwise be interpreted as properties: f.next(); Looks like it advances f, even though next isn't a verb. Without the parentheses, it looks like a noop access of a property.

I disagree, it doesn't look like it advances. With the parens, it just looks like a java-style get-function. To me, at least.
 I'm not too concerned with requiring () on your examples because it's
 inconsequential to me -- having parentheses isn't *less* clear than not
 having them. I don't mind if you wish to allow these calls without
 parens, but there has to still be a way to force the parens.

 -Steve

I disagree. I understand that in some cases we would not want to permit calling with parenthesis, and that calling as assignment is sometimes less than ideal. I do not, however, see any reason to allow forcing of parenthesis for regular functions.
Jan 29 2010
prev sibling next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Steven Schveighoffer wrote:
 On Fri, 29 Jan 2010 13:43:50 -0500, Pelle Månsson 
 <pelle.mansson gmail.com> wrote:
 
 On 01/29/2010 07:10 PM, Steven Schveighoffer wrote:
 Note in the anecdote above, both users would have
 been satisfied if you could *only* call empty without parentheses.

That's a good point. The writeln = 3; is also a good point. :) What I'm trying to defend is the ability to call non-property functions without the parens. I find this: array.stable_sort; file.detach; range.popFront; to look less noisy, clearer and just plain sexier than the respective versions with the parens.

You've cited three functions where the function names cannot be misinterpreted as properties. This is not the case for all function names. If you wish to have a way to specify a function can be called either way, then I think you also need a way to specify that a function can only be called with parentheses. I don't disagree that the above is unambiguous, but there are examples where it is ambiguous. f.read; does this mean read f, or is it an accidental noop fetching a property indicating f is read?

"Rules are not meant to be followed robotically." Sorry I couldn't abstain :o).
 Requiring parentheses also allows you to force meanings where they would 
 otherwise be interpreted as properties:
 
 f.next();
 
 Looks like it advances f, even though next isn't a verb.  Without the 
 parentheses, it looks like a noop access of a property.
 
 I'm not too concerned with requiring () on your examples because it's 
 inconsequential to me -- having parentheses isn't *less* clear than not 
 having them.  I don't mind if you wish to allow these calls without 
 parens, but there has to still be a way to force the parens.
 
 -Steve

Ok how about this: if just calling the thing changes the parent, it can't be a property. Guess I could live with that. Andrei
Jan 29 2010
parent Michel Fortin <michel.fortin michelf.com> writes:
On 2010-01-29 15:02:13 -0500, Andrei Alexandrescu 
<SeeWebsiteForEmail erdani.org> said:

 Ok how about this: if just calling the thing changes the parent, it 
 can't be a property. Guess I could live with that.

Hopefully that rule will only apply to the getter. :-) -- Michel Fortin michel.fortin michelf.com http://michelf.com/
Jan 29 2010
prev sibling parent reply "Nick Sabalausky" <a a.a> writes:
"Pelle Mnsson" <pelle.mansson gmail.com> wrote in message 
news:hjv9sf$1n5o$1 digitalmars.com...
 On 01/29/2010 07:10 PM, Steven Schveighoffer wrote:
 Note in the anecdote above, both users would have
 been satisfied if you could *only* call empty without parentheses.

That's a good point. The writeln = 3; is also a good point. :) What I'm trying to defend is the ability to call non-property functions without the parens. I find this: array.stable_sort; file.detach; range.popFront; to look less noisy, clearer and just plain sexier than the respective versions with the parens.

To me, at a glance, it looks like a series of no-ops. Like "x; y; z;". Only upon closer inspection of the names does it become apperent that functions are actually being called.
Jan 29 2010
parent reply Don <nospam nospam.com> writes:
Nick Sabalausky wrote:
 "Pelle Mnsson" <pelle.mansson gmail.com> wrote in message 
 news:hjv9sf$1n5o$1 digitalmars.com...
 On 01/29/2010 07:10 PM, Steven Schveighoffer wrote:
 Note in the anecdote above, both users would have
 been satisfied if you could *only* call empty without parentheses.

What I'm trying to defend is the ability to call non-property functions without the parens. I find this: array.stable_sort; file.detach; range.popFront; to look less noisy, clearer and just plain sexier than the respective versions with the parens.

To me, at a glance, it looks like a series of no-ops. Like "x; y; z;". Only upon closer inspection of the names does it become apperent that functions are actually being called.

.reverse and .sort MUST be renamed. (Removal would be an acceptable form of renaming IMHO).
Jan 31 2010
parent reply dsimcha <dsimcha yahoo.com> writes:
== Quote from Don (nospam nospam.com)'s article
 Nick Sabalausky wrote:
 "Pelle Mnsson" <pelle.mansson gmail.com> wrote in message
 news:hjv9sf$1n5o$1 digitalmars.com...
 On 01/29/2010 07:10 PM, Steven Schveighoffer wrote:
 Note in the anecdote above, both users would have
 been satisfied if you could *only* call empty without parentheses.

What I'm trying to defend is the ability to call non-property functions without the parens. I find this: array.stable_sort; file.detach; range.popFront; to look less noisy, clearer and just plain sexier than the respective versions with the parens.

To me, at a glance, it looks like a series of no-ops. Like "x; y; z;". Only upon closer inspection of the names does it become apperent that functions are actually being called.

.reverse and .sort MUST be renamed. (Removal would be an acceptable form of renaming IMHO).

Yea, can anyone even come up with a good Devil's Advocate argument in favor of leaving these in? The best one I can think of is that, since arrays in D are builtin, the basic functionality for them should also be builtin so they feel "first-class". This is a pretty weak argument. The builtins made sense early on, but now they are slow, inflexible and not substantially easier to use than the std.algorithm functions.
Jan 31 2010
parent bearophile <bearophileHUGS lycos.com> writes:
dsimcha:
 Yea, can anyone even come up with a good Devil's Advocate argument in favor of
 leaving these in?  The best one I can think of is that, since arrays in D are
 builtin, the basic functionality for them should also be builtin so they feel
 "first-class".  This is a pretty weak argument.  The builtins made sense early
on,
 but now they are slow, inflexible and not substantially easier to use than the
 std.algorithm functions.

I don't know. The built-in sort is certified broken, very slow, and too much rigid. But I like the idea of a language that has built-in some very common operations, especially if it already has built-in data structures (like dynamic arrays and associative arrays. Associative arrays are a complex data structure). The good thing of the built in sort is that if you have to sort small groups of many different types of data, you don't need to import algorithms and your binary doesn't inflate because of all those different instances of the sort templated function. In the end I think that: - The sort method from the dynamic arrays can be removed; - The reverse method can be kept; - More useful methods can be added to the associative arrays, I have written about this in the past few times. Bye, bearophile
Jan 31 2010
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Fri, 29 Jan 2010 12:42:57 -0500, Pelle Månsson  
<pelle.mansson gmail.com> wrote:

 On 01/29/2010 02:01 PM, Steven Schveighoffer wrote:
 That's a deficiency in the design of byLine. It's a range that "primes"
 itself with a line of text. The fact that you can enter the line above
 and just throw away the data seems error prone to me. When would you
 ever use that "feature"? In practice, it doesn't matter, because the
 only purpose to fetch the byLine struct is to iterate data from stdin.

 The design could be fixed with a boolean isPrimed that is unset on the
 first call to front. But like I said, it doesn't matter in the long run,
 since nobody ever fetches byLine without using it.

 I find that the shoehorning of an input range onto a stream is always
 going to have this problem, so there's not much we can do about it. It
 doesn't change the concept that byLine is a property. I find streams
 much better suited to opApply, but I've already had that unsuccessful
 battle, and I don't want to have it again.

So byLine should be a property when implemented as a range, and a function when implemented as an opApply based loop?

I meant byLine should return a struct that implements opApply. If it is a function then you have to pass the address to foreach, which is a little awkward.
 You be the judge: http://www.dsource.org/projects/tango/ticket/1184

 I find the resulting workaround very unsavory.

 -Steve

That's the assignment syntax, which I do agree is weird. Sorry if I was unclear. This is what I thought property was for. It has, however, nothing to do with the omitting of the ().

No, but it is an example of someone misinterpreting the meaning of a function because the compiler accepted his syntax. Yes, the assignment rewrite is more troublesome than the getter, but being able to force someone to omit the parentheses has its advantages: user1: When I call range.empty(), it doesn't clear the range developer: Hm.. empty is not an action, its a property. Maybe I'll fix it by changing it to isEmpty to make it clear. user1: great idea! that's much clearer. .... user2: Why did you name it isEmpty, isn't the 'is' redundant since this looks perfectly normal? if(r.empty) developer: *sigh* This is the problem I ran into. Because so much meaning is attached to the () by humans, you must resort to naming conventions to make the intentions clear, then point out the reasons for not using a better name to future complainers. Note in the anecdote above, both users would have been satisfied if you could *only* call empty without parentheses. The no-parens property requirement has nothing to do with compiler interpretation or functionality and everything to do with human interpretation. It's all about what does the call *look* like it's doing as opposed to what it actually does. By enforcing the removal of parentheses, most normal users don't have to read the docs or look at anything else. It just works the way it's supposed to work, and looks like it does that. This doesn't make every single case clear, nor does it install automatic wisdom in all developers to be able to invent intuitive names. What it does is make it *possible* for you to invent intuitive names that retain their meaning and are succinct. I don't know about you, but using libraries with intuitive, consistent, and succinct terminology is really much more enjoyable than ones with inconsistent or overly verbose terminology. The other benefit is it makes calling delegate properties less ugly and more consistent with analogous fields. -Steve
Jan 29 2010
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Fri, 29 Jan 2010 13:43:50 -0500, Pelle Månsson  
<pelle.mansson gmail.com> wrote:

 On 01/29/2010 07:10 PM, Steven Schveighoffer wrote:
 Note in the anecdote above, both users would have
 been satisfied if you could *only* call empty without parentheses.

That's a good point. The writeln = 3; is also a good point. :) What I'm trying to defend is the ability to call non-property functions without the parens. I find this: array.stable_sort; file.detach; range.popFront; to look less noisy, clearer and just plain sexier than the respective versions with the parens.

You've cited three functions where the function names cannot be misinterpreted as properties. This is not the case for all function names. If you wish to have a way to specify a function can be called either way, then I think you also need a way to specify that a function can only be called with parentheses. I don't disagree that the above is unambiguous, but there are examples where it is ambiguous. f.read; does this mean read f, or is it an accidental noop fetching a property indicating f is read? Requiring parentheses also allows you to force meanings where they would otherwise be interpreted as properties: f.next(); Looks like it advances f, even though next isn't a verb. Without the parentheses, it looks like a noop access of a property. I'm not too concerned with requiring () on your examples because it's inconsequential to me -- having parentheses isn't *less* clear than not having them. I don't mind if you wish to allow these calls without parens, but there has to still be a way to force the parens. -Steve
Jan 29 2010
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Fri, 29 Jan 2010 14:23:55 -0500, Pelle Månsson  
<pelle.mansson gmail.com> wrote:

 On 01/29/2010 08:07 PM, Steven Schveighoffer wrote:
 f.next();

 Looks like it advances f, even though next isn't a verb. Without the
 parentheses, it looks like a noop access of a property.

I disagree, it doesn't look like it advances. With the parens, it just looks like a java-style get-function. To me, at least.

If this were Java, I'd agree with you :) But even on Java, it would have to be getNext().
 I'm not too concerned with requiring () on your examples because it's
 inconsequential to me -- having parentheses isn't *less* clear than not
 having them. I don't mind if you wish to allow these calls without
 parens, but there has to still be a way to force the parens.

I disagree. I understand that in some cases we would not want to permit calling with parenthesis, and that calling as assignment is sometimes less than ideal. I do not, however, see any reason to allow forcing of parenthesis for regular functions.

I guess D can't please everybody all the time. Oh well. -Steve
Jan 29 2010
prev sibling parent Bill Baxter <wbaxter gmail.com> writes:
On Fri, Jan 29, 2010 at 12:02 PM, Andrei Alexandrescu
<SeeWebsiteForEmail erdani.org> wrote:
 Steven Schveighoffer wrote:
 On Fri, 29 Jan 2010 13:43:50 -0500, Pelle M=E5nsson
 <pelle.mansson gmail.com> wrote:

 On 01/29/2010 07:10 PM, Steven Schveighoffer wrote:
 Note in the anecdote above, both users would have
 been satisfied if you could *only* call empty without parentheses.

That's a good point. The writeln =3D 3; is also a good point. :) What I'm trying to defend is the ability to call non-property functions without the parens. I find this: array.stable_sort; file.detach; range.popFront; to look less noisy, clearer and just plain sexier than the respective versions with the parens.

You've cited three functions where the function names cannot be misinterpreted as properties. =A0This is not the case for all function n=


 =A0If you wish to have a way to specify a function can be called either =


 then I think you also need a way to specify that a function can only be
 called with parentheses.

 I don't disagree that the above is unambiguous, but there are examples
 where it is ambiguous.

 f.read;

 does this mean read f, or is it an accidental noop fetching a property
 indicating f is read?

"Rules are not meant to be followed robotically." Sorry I couldn't abstain :o).
 Requiring parentheses also allows you to force meanings where they would
 otherwise be interpreted as properties:

 f.next();

 Looks like it advances f, even though next isn't a verb. =A0Without the
 parentheses, it looks like a noop access of a property.

 I'm not too concerned with requiring () on your examples because it's
 inconsequential to me -- having parentheses isn't *less* clear than not
 having them. =A0I don't mind if you wish to allow these calls without pa=


 but there has to still be a way to force the parens.

 -Steve

Ok how about this: if just calling the thing changes the parent, it can't=

 a property. Guess I could live with that.

Should be "if calling the thing changes the parent in an outwardly visible way". Doing refcounting or caching mutations under the hood should be ok. --bb
Jan 29 2010
prev sibling parent torhu <no spam.invalid> writes:
On 29.01.2010 05:20, Steven Schveighoffer wrote:
 Andrei Alexandrescu Wrote:

  Michiel Helvensteijn wrote:
  >  Andrei Alexandrescu wrote:
  >
  >>>>  foreach (line; stdin.byLine()) { ... }
  >>>>
  >>>>  vs.
  >>>>
  >>>>  foreach (line; stdin.byLine) { ... }
  >>>>
  >>>>  How do I choose?
  >>>  byLine is a property.  It is fetching a range on stdin.
  >>>
  >>>  -Steve
  >>  Damn. I was sure the answer will be different.
  >
  >  byLine() is a function. It changes the state of stdin. Calling it
  >  consecutively will in general result in different return values. If there
  >  were two guys: stdin.currentLine (property) and stdin.nextLine(), it would
  >  be a different story.

No no no. byLine returns a struct, it does not modify stdin. Operating on the struct modifies stdin, but that is outside the call to the property getter. Look at it this way (although this is not the only way to look at it), could byLine be a field inside stdin? It could. You could store a copy of what byLine returns inside stdin, and people could just access it.

Before more time is wasted in this discussion, I would like to point out that byLine does actually have two arguments. I wrote a post about byLine yesterday, but noone seems to have noticed..
Jan 31 2010