digitalmars.D - join
- Andrei Alexandrescu (77/77) Jan 18 2011 I implemented a simple separatorless joiner as follows:
- so (4/11) Jan 18 2011 Didn't know there was a solution to namespace pollution.
- Andrei Alexandrescu (5/16) Jan 18 2011 I plan to, albeit cautiously. Sometimes people would want e.g. to store
- Lutger Blijdestijn (4/23) Jan 24 2011 I do this sometimes with Appender for splitting complex construction of ...
- Ary Manzana (6/8) Jan 19 2011 Hi Andrei,
- Andrei Alexandrescu (22/31) Jan 19 2011 Given a range of ranges, joiner concatenates them all with an optional
- Andrej Mitrovic (2/10) Jan 19 2011 This will be great for string mixins. "int first, int last"
- Lutger Blijdestijn (4/11) Jan 24 2011 I had need for a group() that constructs a range of ranges instead of tu...
- Stanislav Blinov (6/16) Jan 24 2011 I somewhat disagree about Appender. I had situations when I needed to
I implemented a simple separatorless joiner as follows: auto joiner(RoR)(RoR r) if (isInputRange!RoR && isInputRange!(ElementType!RoR)) { static struct Result { private: RoR _items; ElementType!RoR _current; void prime() { for (;; _items.popFront()) { if (_items.empty) return; if (!_items.front.empty) break; } _current = _items.front; _items.popFront(); } public: this(RoR r) { _items = r; prime(); } property auto empty() { return _current.empty; } property auto ref front() { assert(!empty); return _current.front; } void popFront() { assert(!_current.empty); _current.popFront(); if (_current.empty) prime(); } static if (isForwardRange!RoR && isForwardRange!(ElementType!RoR)) { property auto save() { Result copy; copy._items = _items.save; copy._current = _current.save; return copy; } } } return Result(r); } The code has a few properties that I'd like to discuss a bit: 1. It doesn't provide bidirectional primitives, although it often could. The rationale is that implementing back and popBack incurs size and time overheads that are difficult to justify. Most of the time people just want to join stuff and go through it forward. The counterargument is that providing those primitives would make join more interesting and opens the door to other idioms. What say you? 2. joiner uses an idiom that I've experimented with in the past: it defines a local struct and returns it. As such, joiner's type is impossible to express without auto. I find that idiom interesting for many reasons, among which the simplest is that the code is terse, compact, and doesn't pollute the namespace. I'm thinking we should do the same for Appender - it doesn't make much sense to create an Appender except by calling the appender() function. 3. Walter, Don, kindly please fix ddoc so it works with auto. What used to be an annoyance becomes a disabler for the idiom above. Currently it is impossible to document joiner (aside from unsavory tricks). 4. I found the prime() idiom quite frequent when defining ranges. Essentially prime() positions the troops by the border. Both the constructor and popFront() call prime(). 5. auto and auto ref rock - they allow simple, correct definitions. 6. Currently joiner() has a bug: it will not work as expected for certain ranges. Which ranges are those, and how can the bug be fixed? Andrei
Jan 18 2011
2. joiner uses an idiom that I've experimented with in the past: it defines a local struct and returns it. As such, joiner's type is impossible to express without auto. I find that idiom interesting for many reasons, among which the simplest is that the code is terse, compact, and doesn't pollute the namespace. I'm thinking we should do the same for Appender - it doesn't make much sense to create an Appender except by calling the appender() function.Didn't know there was a solution to namespace pollution. This one is a very nice idea, are you planning to use it in phobos in general? Retro, Stride... there should be many.
Jan 18 2011
On 1/18/11 2:55 PM, so wrote:I plan to, albeit cautiously. Sometimes people would want e.g. to store a member of that type in a class. They still can by saying typeof(joiner(...)) but we don't want to make it awkward for them. Andrei2. joiner uses an idiom that I've experimented with in the past: it defines a local struct and returns it. As such, joiner's type is impossible to express without auto. I find that idiom interesting for many reasons, among which the simplest is that the code is terse, compact, and doesn't pollute the namespace. I'm thinking we should do the same for Appender - it doesn't make much sense to create an Appender except by calling the appender() function.Didn't know there was a solution to namespace pollution. This one is a very nice idea, are you planning to use it in phobos in general? Retro, Stride... there should be many.
Jan 18 2011
Andrei Alexandrescu wrote:On 1/18/11 2:55 PM, so wrote:I do this sometimes with Appender for splitting complex construction of a string between functions. Is that bad practice? What is the alternative idiom? If possible, please reconsider making Appender an existential type.I plan to, albeit cautiously. Sometimes people would want e.g. to store a member of that type in a class. They still can by saying typeof(joiner(...)) but we don't want to make it awkward for them. Andrei2. joiner uses an idiom that I've experimented with in the past: it defines a local struct and returns it. As such, joiner's type is impossible to express without auto. I find that idiom interesting for many reasons, among which the simplest is that the code is terse, compact, and doesn't pollute the namespace. I'm thinking we should do the same for Appender - it doesn't make much sense to create an Appender except by calling the appender() function.Didn't know there was a solution to namespace pollution. This one is a very nice idea, are you planning to use it in phobos in general? Retro, Stride... there should be many.
Jan 24 2011
On 1/18/11 4:25 PM, Andrei Alexandrescu wrote:I implemented a simple separatorless joiner as follows: auto joiner(RoR)(RoR r)Hi Andrei, What does it do? How do you use it? And why "prime"? When I read it I remember the meaning of "prime number". I just looked up in the dictionary, it seems it also means "prepare". Why not use a simpler language and call it "prepare"?
Jan 19 2011
On 1/19/11 11:39 AM, Ary Manzana wrote:On 1/18/11 4:25 PM, Andrei Alexandrescu wrote:Given a range of ranges, joiner concatenates them all with an optional separator. It's just like today's join(). The interesting part is that joiner never allocates memory or copy data - it operates directly on the original ranges. All it needs to do is keep track where it is. Moreover, if you decide to stop the iteration early, some work is saved. import std.algorithm, std.stdio; void main() { auto stuff = [ "coat", "husky", "sled", ]; writeln(joiner(stuff)); writeln(joiner(stuff, "; ")); } writes: coathuskysled coat; husky; sled In brief you can in many places replace join() with joiner() and enjoy fewer memory allocations and less copies.I implemented a simple separatorless joiner as follows: auto joiner(RoR)(RoR r)Hi Andrei, What does it do? How do you use it?And why "prime"? When I read it I remember the meaning of "prime number". I just looked up in the dictionary, it seems it also means "prepare". Why not use a simpler language and call it "prepare"?Good idea, done. Will be part of the next commit. I plan to make one more pass through std.algorithm anyway. If there's stuff you wish were there (including stuff generalized from other modules), please let me know. Andrei
Jan 19 2011
On 1/19/11, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:import std.algorithm, std.stdio; void main() { auto stuff = [ "coat", "husky", "sled", ]; writeln(joiner(stuff)); writeln(joiner(stuff, "; ")); } coat; husky; sledThis will be great for string mixins. "int first, int last"
Jan 19 2011
Andrei Alexandrescu wrote: ...Good idea, done. Will be part of the next commit. I plan to make one more pass through std.algorithm anyway. If there's stuff you wish were there (including stuff generalized from other modules), please let me know. AndreiI had need for a group() that constructs a range of ranges instead of tuple with count.
Jan 24 2011
18.01.2011 22:25, Andrei Alexandrescu пишет:I implemented a simple separatorless joiner as follows: ... The code has a few properties that I'd like to discuss a bit: 2. joiner uses an idiom that I've experimented with in the past: it defines a local struct and returns it. As such, joiner's type is impossible to express without auto. I find that idiom interesting for many reasons, among which the simplest is that the code is terse, compact, and doesn't pollute the namespace. I'm thinking we should do the same for Appender - it doesn't make much sense to create an Appender except by calling the appender() function.I somewhat disagree about Appender. I had situations when I needed to store an Appender as a class/struct member (i.e. one may build an output range on top of it). Appender!T looks better than ReturnType!(appender!T()), IMHO. Of course, one could always alias that ReturnType, so it's not *that* much of a problem.
Jan 24 2011