Either I totally failed to understand how it's supposed to work, or these lfuns are quite non-functional:
class T(string t){ T `+=(string s){ t+=s;return this; } } T o = T(""); o->t;
(7) Result: ""
o+="bar";
Incompatible types Unknown program: `+(HilfeInput()->T(),"bar")
Obviously Pike is calling `+(o, "bar"), and ignoring the existence of lfun::`+=() in T...
Indeed. A test script: #!/usr/local/bin/pike -rt
class T(string t) { T `+=(string s) { werror("calling T->`+=(%O)\n", s); t += s; return this; }
T `+(string...args) { werror("calling T->`+(%s)\n", sprintf("%O",args[*])*","); return T(t + predef::`+(@args) ); } }
int main() { T o = T("bar"); T p = o; o += "foo"; write("o->t == %s\n", o->t); write("p->t == %s\n", p->t); return 0; }
Under 7.4.13 it prints calling T->`+("foo") o->t == barfoo p->t == bar
/ rjb
Previous text:
2003-04-17 21:23: Subject: lfun::`+=()
Either I totally failed to understand how it's supposed to work, or these lfuns are quite non-functional:
class T(string t){ T `+=(string s){ t+=s;return this; } } T o = T(""); o->t;
(7) Result: ""
o+="bar";
Incompatible types Unknown program: `+(HilfeInput()->T(),"bar")
Obviously Pike is calling `+(o, "bar"), and ignoring the existence of lfun::`+=() in T...
/ rjb
Yes. The reason is that the object got more than one reference (one is in o and one is on the stack) and in that case pike won't use the destructive `+= since it wouldn't follow the semantics of the += operator.
An optimization for this has been added in 7.5 recently so that it doesn't trip up on the extra reference from the stack. Your example works there.
In 7.4 and earlier you have to get rid of one reference, which can be done with this trick:
o = o + (o = 0, "bar");
Despite the appearance, pike will use o->`+= since the object only got one reference (on the stack, since o is temporarily set to 0).
/ Martin Stjernholm, Roxen IS
Previous text:
2003-04-17 21:23: Subject: lfun::`+=()
Either I totally failed to understand how it's supposed to work, or these lfuns are quite non-functional:
class T(string t){ T `+=(string s){ t+=s;return this; } } T o = T(""); o->t;
(7) Result: ""
o+="bar";
Incompatible types Unknown program: `+(HilfeInput()->T(),"bar")
Obviously Pike is calling `+(o, "bar"), and ignoring the existence of lfun::`+=() in T...
/ rjb
Note (to Grubba): It doesn't work with
o += (o = 0, "bar");
since the evaluation order is the equivalent of
mixed tmp = (o = 0, "bar"); o += tmp;
Thus o will hold "0bar" afterwards.
/ Martin Stjernholm, Roxen IS
Previous text:
2003-04-17 22:26: Subject: lfun::`+=()
Yes. The reason is that the object got more than one reference (one is in o and one is on the stack) and in that case pike won't use the destructive `+= since it wouldn't follow the semantics of the += operator.
An optimization for this has been added in 7.5 recently so that it doesn't trip up on the extra reference from the stack. Your example works there.
In 7.4 and earlier you have to get rid of one reference, which can be done with this trick:
o = o + (o = 0, "bar");
Despite the appearance, pike will use o->`+= since the object only got one reference (on the stack, since o is temporarily set to 0).
/ Martin Stjernholm, Roxen IS
Ah, now I understand the scribblings on Grubba's whiteboard. :-)
/ Johan Sundström (folkskådare)
Previous text:
2003-04-17 22:26: Subject: lfun::`+=()
Yes. The reason is that the object got more than one reference (one is in o and one is on the stack) and in that case pike won't use the destructive `+= since it wouldn't follow the semantics of the += operator.
An optimization for this has been added in 7.5 recently so that it doesn't trip up on the extra reference from the stack. Your example works there.
In 7.4 and earlier you have to get rid of one reference, which can be done with this trick:
o = o + (o = 0, "bar");
Despite the appearance, pike will use o->`+= since the object only got one reference (on the stack, since o is temporarily set to 0).
/ Martin Stjernholm, Roxen IS
Duh. When the object o has no references outside the stack, I don't care whether o+="foo" is destructive or not; I can't tell the difference anyway.
OTOH there seems to be no problem in defining a lfun::`+() that acts destructively (returns `this')...
/ rjb
Previous text:
2003-04-17 22:26: Subject: lfun::`+=()
Yes. The reason is that the object got more than one reference (one is in o and one is on the stack) and in that case pike won't use the destructive `+= since it wouldn't follow the semantics of the += operator.
An optimization for this has been added in 7.5 recently so that it doesn't trip up on the extra reference from the stack. Your example works there.
In 7.4 and earlier you have to get rid of one reference, which can be done with this trick:
o = o + (o = 0, "bar");
Despite the appearance, pike will use o->`+= since the object only got one reference (on the stack, since o is temporarily set to 0).
/ Martin Stjernholm, Roxen IS
You will be able to tell the difference if o->t is a couple of megabytes and you're adding lots of small strings to it, I promise.
OTOH there seems to be no problem in defining a lfun::`+() that acts destructively (returns `this')...
Please don't do that. It doesn't follow the semantics of the + operator, and so will seriously confuse anyone who is using your class. Just name your destructive function something like "append" or "add" instead.
/ Martin Stjernholm, Roxen IS
Previous text:
2003-04-17 22:46: Subject: lfun::`+=()
Duh. When the object o has no references outside the stack, I don't care whether o+="foo" is destructive or not; I can't tell the difference anyway.
OTOH there seems to be no problem in defining a lfun::`+() that acts destructively (returns `this')...
/ rjb
Well, operator overloading is always risky business: you have to balance the syntactic convenience against the potential confusion... Adequate documentation is IMHO a good palliative, but you may differ.
Anyway, to a mathematician at least, the basic semantics of `+' is commutativity, and that is violated as soon as you define addition of strings to mean concatenation.
Moreover, it becomes hard to make any sensible use of operator overloading once you can't reliably predict which lfun will be called in evaluating (say) `a+b', without inspecting all the surrounding code...
/ rjb
Previous text:
2003-04-17 23:00: Subject: lfun::`+=()
You will be able to tell the difference if o->t is a couple of megabytes and you're adding lots of small strings to it, I promise.
OTOH there seems to be no problem in defining a lfun::`+() that acts destructively (returns `this')...
Please don't do that. It doesn't follow the semantics of the + operator, and so will seriously confuse anyone who is using your class. Just name your destructive function something like "append" or "add" instead.
/ Martin Stjernholm, Roxen IS
There is an obvious difference between mathematical addition and the + operator in Pike. It's only the latter that's interesting here.
The + operator is not commutative in Pike; see predef::`+() in the refdoc. (It was considered commutative in 7.0; Pike could change the order back then.)
The + operator is also not destructive on either argument in Pike. The refdoc says that implicitly since the reverse always is documented (or at least it should be).
So given that one should not make an lfun that causes predef::`+ to go against its documentation then the expected behavior of the lfun `+ is fairly well documented. Granted, it could be documented better for the lfun too.
There's no need to figure out if an expression a+b is destructive, since if it is then Pike ensures that the destructivity doesn't have any side effects, under the assumption that the lfuns are correctly implemented. The lfun `+= only works as a more optimized alternative to `+ that Pike can use in that case. If one _have_ to figure out which of the lfuns `+ and `+= that are called in a certain case then they aren't implemented right.
Perhaps it'd be better if `+= had another name, say `destructive_add, so that it wasn't confused so easily with the += operator.
I see that `+= lacked documentation. I've fixed that now.
/ Martin Stjernholm, Roxen IS
Previous text:
2003-04-17 23:22: Subject: lfun::`+=()
Well, operator overloading is always risky business: you have to balance the syntactic convenience against the potential confusion... Adequate documentation is IMHO a good palliative, but you may differ.
Anyway, to a mathematician at least, the basic semantics of `+' is commutativity, and that is violated as soon as you define addition of strings to mean concatenation.
Moreover, it becomes hard to make any sensible use of operator overloading once you can't reliably predict which lfun will be called in evaluating (say) `a+b', without inspecting all the surrounding code...
/ rjb
In such case, I think the description of iterators (such as there is), under the refdoc item for lfun::_get_iterator(), should also be updated, to make it clear that a `+() is also required, as `+=() alone might not work in some cases.
/ rjb
Previous text:
2003-04-18 00:53: Subject: lfun::`+=()
There is an obvious difference between mathematical addition and the + operator in Pike. It's only the latter that's interesting here.
The + operator is not commutative in Pike; see predef::`+() in the refdoc. (It was considered commutative in 7.0; Pike could change the order back then.)
The + operator is also not destructive on either argument in Pike. The refdoc says that implicitly since the reverse always is documented (or at least it should be).
So given that one should not make an lfun that causes predef::`+ to go against its documentation then the expected behavior of the lfun `+ is fairly well documented. Granted, it could be documented better for the lfun too.
There's no need to figure out if an expression a+b is destructive, since if it is then Pike ensures that the destructivity doesn't have any side effects, under the assumption that the lfuns are correctly implemented. The lfun `+= only works as a more optimized alternative to `+ that Pike can use in that case. If one _have_ to figure out which of the lfuns `+ and `+= that are called in a certain case then they aren't implemented right.
Perhaps it'd be better if `+= had another name, say `destructive_add, so that it wasn't confused so easily with the += operator.
I see that `+= lacked documentation. I've fixed that now.
/ Martin Stjernholm, Roxen IS
You got a point. The API documented there is enough for iterators to work with foreach, but that's far from the only purpose with them.
/ Martin Stjernholm, Roxen IS
Previous text:
2003-04-18 10:38: Subject: lfun::`+=()
In such case, I think the description of iterators (such as there is), under the refdoc item for lfun::_get_iterator(), should also be updated, to make it clear that a `+() is also required, as `+=() alone might not work in some cases.
/ rjb
I've now improved the doc for iterators by adding an interface class Iterator. In the process I fixed some bugs, such as that most of the iterators for the builtin types had `! that was practically inverted.
/ Martin Stjernholm, Roxen IS
Previous text:
2003-04-18 12:26: Subject: lfun::`+=()
You got a point. The API documented there is enough for iterators to work with foreach, but that's far from the only purpose with them.
/ Martin Stjernholm, Roxen IS
Note that Stdio.File sports an lfun::`<<() that doesn't comply with the rules you advocated here. I don't see much difference in this respect between + and <<, other than the latter being less commonly used.
/ rjb
Previous text:
2003-04-18 00:53: Subject: lfun::`+=()
There is an obvious difference between mathematical addition and the + operator in Pike. It's only the latter that's interesting here.
The + operator is not commutative in Pike; see predef::`+() in the refdoc. (It was considered commutative in 7.0; Pike could change the order back then.)
The + operator is also not destructive on either argument in Pike. The refdoc says that implicitly since the reverse always is documented (or at least it should be).
So given that one should not make an lfun that causes predef::`+ to go against its documentation then the expected behavior of the lfun `+ is fairly well documented. Granted, it could be documented better for the lfun too.
There's no need to figure out if an expression a+b is destructive, since if it is then Pike ensures that the destructivity doesn't have any side effects, under the assumption that the lfuns are correctly implemented. The lfun `+= only works as a more optimized alternative to `+ that Pike can use in that case. If one _have_ to figure out which of the lfuns `+ and `+= that are called in a certain case then they aren't implemented right.
Perhaps it'd be better if `+= had another name, say `destructive_add, so that it wasn't confused so easily with the += operator.
I see that `+= lacked documentation. I've fixed that now.
/ Martin Stjernholm, Roxen IS
That's a C++-ism that someone thought Pike needed, I don't know why. I'd like to obsolete it.
/ Martin Stjernholm, Roxen IS
Previous text:
2003-04-18 22:51: Subject: lfun::`+=()
Note that Stdio.File sports an lfun::`<<() that doesn't comply with the rules you advocated here. I don't see much difference in this respect between + and <<, other than the latter being less commonly used.
/ rjb
I think that is a rather safe operation; AFAIK it does not even work.
/ Johan Sundström (folkskådare)
Previous text:
2003-04-18 23:11: Subject: lfun::`+=()
That's a C++-ism that someone thought Pike needed, I don't know why. I'd like to obsolete it.
/ Martin Stjernholm, Roxen IS
I don't see why being able to write
fd << "Hello world.";
instead of
fd->write("Hello world.");
is a problem of any sort. Sure, it's not terribly useful, but there is little likelihood of any serious confusion: `<< has no predefined semantics for anything other than ints, so it is pretty much free to do anything as long as this is properly documented for the class that defines an lfun::`<<. The only issue being whether this leads to a convenient notation that makes some sense once you know how it works (which is of course rather subjective).
/ rjb
Previous text:
2003-04-18 23:11: Subject: lfun::`+=()
That's a C++-ism that someone thought Pike needed, I don't know why. I'd like to obsolete it.
/ Martin Stjernholm, Roxen IS
When evaluating a feature I'm more inclined to ask "what's the benefit?" rather than "is it harmless?". In this case I can see no benefit, but actually some harm since the very existence require people to learn about it, at least when they happen to come across it in some code.
The syntax is not good since it has no relation with the normal meaning of the shift operators, which means that people are forced to look it up in the docs and remember it. "write" is much better since it in itself fairly well describes what's going on.
Another bad thing with Stdio.File.`<< is that it's a very incomplete attempt at implementing the C++ stream interface. There's no corresponding Stdio.File.`>> as one would expect, and no objects overloads `<< and `>> for marshalling (there's _encode, _decode and _sprintf for that). Thus it's just an oddball function that's completely out of place in Stdio.File.
But as you say this lfun is not in the way, so there's no real need to remove it in the near future so that #pike is required. It's enough to deprecate it in the manual to limit the risk that new code actually uses it.
/ Martin Stjernholm, Roxen IS
Previous text:
2003-04-23 12:39: Subject: lfun::`+=()
I don't see why being able to write
fd << "Hello world.";
instead of
fd->write("Hello world.");
is a problem of any sort. Sure, it's not terribly useful, but there is little likelihood of any serious confusion: `<< has no predefined semantics for anything other than ints, so it is pretty much free to do anything as long as this is properly documented for the class that defines an lfun::`<<. The only issue being whether this leads to a convenient notation that makes some sense once you know how it works (which is of course rather subjective).
/ rjb
The + operator is not commutative in Pike; see predef::`+() in the refdoc. (It was considered commutative in 7.0; Pike could change the order back then.)
Just a detail -- but I believe you are talking about associativity here, rather than commutativity:
(a+b)+c == a+(b+c); // associativity a+b == b+a; // commutativity
/ rjb
Previous text:
2003-04-18 00:53: Subject: lfun::`+=()
There is an obvious difference between mathematical addition and the + operator in Pike. It's only the latter that's interesting here.
The + operator is not commutative in Pike; see predef::`+() in the refdoc. (It was considered commutative in 7.0; Pike could change the order back then.)
The + operator is also not destructive on either argument in Pike. The refdoc says that implicitly since the reverse always is documented (or at least it should be).
So given that one should not make an lfun that causes predef::`+ to go against its documentation then the expected behavior of the lfun `+ is fairly well documented. Granted, it could be documented better for the lfun too.
There's no need to figure out if an expression a+b is destructive, since if it is then Pike ensures that the destructivity doesn't have any side effects, under the assumption that the lfuns are correctly implemented. The lfun `+= only works as a more optimized alternative to `+ that Pike can use in that case. If one _have_ to figure out which of the lfuns `+ and `+= that are called in a certain case then they aren't implemented right.
Perhaps it'd be better if `+= had another name, say `destructive_add, so that it wasn't confused so easily with the += operator.
I see that `+= lacked documentation. I've fixed that now.
/ Martin Stjernholm, Roxen IS
No, I meant commutativity. But now when I read the note on the 7.0 behavior, I think it's possible to interpret it as only the associativity was undefined. Someone knowing the facts is welcome to clarify that note.
/ Martin Stjernholm, Roxen IS
Previous text:
2003-04-21 01:56: Subject: lfun::`+=()
The + operator is not commutative in Pike; see predef::`+() in the refdoc. (It was considered commutative in 7.0; Pike could change the order back then.)
Just a detail -- but I believe you are talking about associativity here, rather than commutativity:
(a+b)+c == a+(b+c); // associativity a+b == b+a; // commutativity
/ rjb
Where is that note? I vaguely recall having read something like that at some time in the past, but I can't find it now. I do believe I understood it as meaning the order of evaluation was undefined, as opposed to the order of the summands -- note that rearranging the summands changes the result already when dealing with strings. But my memory might be wrong of course.
(Not that this is of any more than historical interest, or terribly relevant to the issues at hand; I'm just curious)
/ rjb
Previous text:
2003-04-23 00:11: Subject: lfun::`+=()
No, I meant commutativity. But now when I read the note on the 7.0 behavior, I think it's possible to interpret it as only the associativity was undefined. Someone knowing the facts is welcome to clarify that note.
/ Martin Stjernholm, Roxen IS
The note is in the refdoc for predef::`+.
-- note that rearranging the summands changes the result already when dealing with strings. /.../
Of course. I'm fairly certain that no pike <= 7.0 did any rearranging when strings were involved.
/ Martin Stjernholm, Roxen IS
Previous text:
2003-04-23 09:03: Subject: lfun::`+=()
Where is that note? I vaguely recall having read something like that at some time in the past, but I can't find it now. I do believe I understood it as meaning the order of evaluation was undefined, as opposed to the order of the summands -- note that rearranging the summands changes the result already when dealing with strings. But my memory might be wrong of course.
(Not that this is of any more than historical interest, or terribly relevant to the issues at hand; I'm just curious)
/ rjb
The note alludes to the sentence immediately above it:
Otherwise if there are more than 2 arguments the result will be: `+(`+(arg1, arg2), @extras)
/ Henrik Grubbström (Lysator)
Previous text:
2003-04-23 19:44: Subject: lfun::`+=()
The note is in the refdoc for predef::`+.
-- note that rearranging the summands changes the result already when dealing with strings. /.../
Of course. I'm fairly certain that no pike <= 7.0 did any rearranging when strings were involved.
/ Martin Stjernholm, Roxen IS
That connection isn't obvious since the two sentences are in different sections, so I still think it could be more clear.
/ Martin Stjernholm, Roxen IS
Previous text:
2003-04-23 19:51: Subject: lfun::`+=()
The note alludes to the sentence immediately above it:
Otherwise if there are more than 2 arguments the result will be: `+(`+(arg1, arg2), @extras)
/ Henrik Grubbström (Lysator)
Commutability has been well-defined since the right-associative lfuns were introduced (ie 1997-10-11 06:48:24, Pike 0.5-971105). Associativity has been well-defined for `+ and `* since 2000-09-22 (Pike 7.1.10).
/ Henrik Grubbström (Lysator)
Previous text:
2003-04-23 00:11: Subject: lfun::`+=()
No, I meant commutativity. But now when I read the note on the 7.0 behavior, I think it's possible to interpret it as only the associativity was undefined. Someone knowing the facts is welcome to clarify that note.
/ Martin Stjernholm, Roxen IS
pike-devel@lists.lysator.liu.se