www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Should formattedWrite take the outputrange by ref?

reply "Tobias Pankrath" <tobias pankrath.net> writes:
I want to print a tree structure and need to keep track of the 
indention for different parts of the tree. My idea was to write a 
generic wrapper for an output range that outputs tabs when it 
encounters a newline. This wrapper has internal state and if I 
want to use formattedWrite with this wrapper than state changes 
don't propagate to the calling context because by value semantics.

Short solution: I'm using a class now.  But shouldn't 
formattedWrite take it's output range by ref? Does anyone else 
have a use case for this and might this cause any problems?
Jan 18 2014
next sibling parent reply "monarch_dodra" <monarchdodra gmail.com> writes:
On Saturday, 18 January 2014 at 21:55:54 UTC, Tobias Pankrath 
wrote:
 I want to print a tree structure and need to keep track of the 
 indention for different parts of the tree. My idea was to write 
 a generic wrapper for an output range that outputs tabs when it 
 encounters a newline. This wrapper has internal state and if I 
 want to use formattedWrite with this wrapper than state changes 
 don't propagate to the calling context because by value 
 semantics.

 Short solution: I'm using a class now.  But shouldn't 
 formattedWrite take it's output range by ref? Does anyone else 
 have a use case for this and might this cause any problems?
*I* think it should. File a report, and I'll see what I can do about it. The problem with these kinds of things though might be breaking existing code...
Jan 18 2014
parent reply "bearophile" <bearophileHUGS lycos.com> writes:
monarch_dodra:

 *I* think it should. File a report, and I'll see what I can do 
 about it. The problem with these kinds of things though might 
 be breaking existing code...
Given the frequency of bugs caused by such functions that require a pointer to the data, I think that a breaking change is the smaller problem. Bye, bearophile
Jan 18 2014
parent reply "Tobias Pankrath" <tobias pankrath.net> writes:
On Saturday, 18 January 2014 at 22:58:59 UTC, bearophile wrote:
 monarch_dodra:

 *I* think it should. File a report, and I'll see what I can do 
 about it. The problem with these kinds of things though might 
 be breaking existing code...
Given the frequency of bugs caused by such functions that require a pointer to the data, I think that a breaking change is the smaller problem. Bye, bearophile
I actually didn't think that a ptr (to output range) would work. This way we can have best of both worlds and I'm happy with it.
Jan 18 2014
parent reply "monarch_dodra" <monarchdodra gmail.com> writes:
On Saturday, 18 January 2014 at 23:06:42 UTC, Tobias Pankrath 
wrote:
 I actually didn't think that a ptr (to output range) would 
 work. This way we can have best of both worlds and I'm happy 
 with it.
A fun fact is that since "." notation works with pointers, more often than not, if "T" verifies some trait "isOutputRange", more often than not, so will "T*". But this is more of a by-product than an actual rule, and, as a rule of thumb, may not be something you want to rely on in a general sense. Limitations include: Type checking: If "R" is a random access range, "R*" will only be an input range, because "p.save" will return an "R", and not an "R*" :/ Also, it is limited to member functions, and not generic UFCS: For example, while in the general sense, "R is input range" => "R* is input range", this will fail for "T[]*", because slices have a non-member popFront, so "p.popFront()" will not actually match a function, and "T[]*" will fail the input range validation :/ So, my conclusion, "*" might be a workable solution. But simply taking by ref would be cleaner, and make more sense as a whole.
Jan 19 2014
parent reply "Tobias Pankrath" <tobias pankrath.net> writes:
On Sunday, 19 January 2014 at 15:03:13 UTC, monarch_dodra wrote:

 So, my conclusion, "*" might be a workable solution. But simply 
 taking by ref would be cleaner, and make more sense as a whole.
Or a special template constraint path for T*. foo(T)(T t) if (is(T = Q*)) && manyOtherChecks!(Q) foo(T)(T t) if (!is(T = Q*)) && manyOtherChecks!(T) Maybe that will break less code.
Jan 19 2014
parent reply "Tobias Pankrath" <tobias pankrath.net> writes:
On Sunday, 19 January 2014 at 15:12:07 UTC, Tobias Pankrath wrote:
 On Sunday, 19 January 2014 at 15:03:13 UTC, monarch_dodra wrote:

 So, my conclusion, "*" might be a workable solution. But 
 simply taking by ref would be cleaner, and make more sense as 
 a whole.
Or a special template constraint path for T*. foo(T)(T t) if (is(T = Q*)) && manyOtherChecks!(Q) foo(T)(T t) if (!is(T = Q*)) && manyOtherChecks!(T) Maybe that will break less code.
But maybe we really should go for taking the output range by reference. See https://d.puremagic.com/issues/show_bug.cgi?id=10291 https://d.puremagic.com/issues/show_bug.cgi?id=9102 Created a new report for this: https://d.puremagic.com/issues/show_bug.cgi?id=11951
Jan 19 2014
parent reply "monarch_dodra" <monarchdodra gmail.com> writes:
On Sunday, 19 January 2014 at 15:28:04 UTC, Tobias Pankrath wrote:
 On Sunday, 19 January 2014 at 15:12:07 UTC, Tobias Pankrath 
 wrote:
 On Sunday, 19 January 2014 at 15:03:13 UTC, monarch_dodra 
 wrote:

 So, my conclusion, "*" might be a workable solution. But 
 simply taking by ref would be cleaner, and make more sense as 
 a whole.
Or a special template constraint path for T*. foo(T)(T t) if (is(T = Q*)) && manyOtherChecks!(Q) foo(T)(T t) if (!is(T = Q*)) && manyOtherChecks!(T) Maybe that will break less code.
But maybe we really should go for taking the output range by reference. See https://d.puremagic.com/issues/show_bug.cgi?id=10291 https://d.puremagic.com/issues/show_bug.cgi?id=9102 Created a new report for this: https://d.puremagic.com/issues/show_bug.cgi?id=11951
Thanks! I'll look into these.
Jan 19 2014
parent reply "Guillaume Chatelet" <chatelet.guillaume gmail.com> writes:
+1 I've been bitten by this also.
Sep 03 2014
parent reply =?UTF-8?B?Ik3DoXJjaW8=?= Martins" <mmartins moovmoov.com> writes:
On Wednesday, 3 September 2014 at 07:43:20 UTC, Guillaume
Chatelet wrote:
 +1 I've been bitten by this also.
Same here, +1
Sep 04 2014
parent "monarch_dodra" <monarchdodra gmail.com> writes:
On Thursday, 4 September 2014 at 17:06:00 UTC, Márcio Martins 
wrote:
 On Wednesday, 3 September 2014 at 07:43:20 UTC, Guillaume
 Chatelet wrote:
 +1 I've been bitten by this also.
Same here, +1
It's still on my radar, but it's actually not that trivial of a change, especially if we want to avoid breaking code, and binary bloat...
Sep 04 2014
prev sibling parent "anonymous" <anonymous example.com> writes:
On Saturday, 18 January 2014 at 21:55:54 UTC, Tobias Pankrath
wrote:
 I want to print a tree structure and need to keep track of the 
 indention for different parts of the tree. My idea was to write 
 a generic wrapper for an output range that outputs tabs when it 
 encounters a newline. This wrapper has internal state and if I 
 want to use formattedWrite with this wrapper than state changes 
 don't propagate to the calling context because by value 
 semantics.

 Short solution: I'm using a class now.
Alternatively, pass a pointer: formattedWrite(&writer, ...)
Jan 18 2014