www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Re: D as a prototyping language (for C/C++ projects)

reply "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Tue, Feb 26, 2013 at 10:01:59PM +0100, Jacob Carlborg wrote:
[.[..]
 Return the date from two days ago:
 
 Ruby on Rails:
 2.days.ago
 Date.today
 Time.now
 
 D:
 Clock.currTime - 2.days
 // Not sure how to do the other two in D
 
 This is not that bad but it's a bit less intuitive. Here we also
 have shortening of "current" which just saves three characters, for
 no reason.

I find the Phobos version more readable, actually. Writing "2.days.ago" is all neat and clever and everything, but the logician in me protests at what all those '.'s are referring to, and they do. Code is not English, and when it pretends to be English, it makes me suspicious that something is subtle going on that I'm not aware of. And when I'm coding, that's something I don't like -- I need to have the assurance I know exactly what's going on. And yes I can learn to parse "2.days.ago" eventually, but it's just additional mental load for only superficial convenience. But YMMV.
 I think it's mostly std.algorithm that is the problem.
 
 * reduce - The "reduce" function is really weird. It can't be used as
 a property. The signature is:
 
 reduce!(fun)(seed, range)
 
 When it should be:
 
 reduce!(seed, fun)(range)
 
 And:
 
 reduce!(fun)(range, seed)

IMHO this is just bikeshedding. I actually find Phobos' order more intuitive (to me anyway), because the function you're reducing on, ideally, should be inlined, so it makes sense to pass it as a compile-time parameter, and the seed value is what you start with, so it makes sense to have it appear as the first parameter. But I can see where UFCS will fail to kick in here, which makes it a bit annoying, I suppose. But reduce was designed before UFCS made it into DMD.
 * No algorithm functions for associative arrays.

Yeah that area needs some work.
 * tap - Ruby has a really nice function, "tap". In D it would look like:
 
 T (func, T) (T t)
 {
     func(t);
     return t;
 }
 
 You can do things like:
 
 Foo foo ()
 {
     return (new Foo).tap!((f) {
         f.x = 3;
 	f.y = 3;
     });
 }

Couldn't you use map for this purpose? On Tue, Feb 26, 2013 at 10:04:50PM +0100, Jacob Carlborg wrote:
 On 2013-02-26 20:52, H. S. Teoh wrote:
 
Do you have any specific examples?

Some more: isBlank and the opposite isPresent. These exists in Ruby on Rails, this is my D version: https://github.com/jacob-carlborg/mambo/blob/master/mambo/core/core.d

Unfortunately, on this point I have to disagree. I find !isBlank much better. Generally, I prefer a more minimal API, but I suppose people coming from Ruby might expect a more "rich" kind of API design (caveat: I don't know Ruby). Having too many ways of stating the same thing makes me wonder if there's some subtle bug lurking somewhere. What if isPresent is not 100% equivalent to !isBlank? And I don't mean just hypothetically; I've seen cases of libraries where bugs cause two supposedly-opposite functions to be not exactly opposite, and then code starts to depend on the buggy behaviour, causing hidden bugs later when the code gets fixed, etc.. A lot of unnecessary problems when you could have just written !isBlank in the first place. Now, I used to be a Perl fanatic, so I totally understand TIMTOWTDI and all that, but I think having a separate function just to encode !isBlank is a bit too extreme. The language has boolean operators for a reason, after all. T -- If you look at a thing nine hundred and ninety-nine times, you are perfectly safe; if you look at it the thousandth time, you are in frightful danger of seeing it for the first time. -- G. K. Chesterton
Feb 26 2013
next sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 2/26/2013 1:26 PM, H. S. Teoh wrote:
 Having too many ways of stating the
 same thing makes me wonder if there's some subtle bug lurking somewhere.
 What if isPresent is not 100% equivalent to !isBlank? And I don't mean
 just hypothetically; I've seen cases of libraries where bugs cause two
 supposedly-opposite functions to be not exactly opposite, and then code
 starts to depend on the buggy behaviour, causing hidden bugs later when
 the code gets fixed, etc.. A lot of unnecessary problems when you could
 have just written !isBlank in the first place.

This is a subtle but very important point.
Feb 26 2013
parent Jacob Carlborg <doob me.com> writes:
On 2013-02-27 03:52, Walter Bright wrote:

 This is a subtle but very important point.

It's not about adding the inverse of an already existing function. It's about adding a function that doesn't exist at all. Don't you read the post and the code at all? Or do I express myself so badly? -- /Jacob Carlborg
Feb 27 2013
prev sibling next sibling parent reply Jacob Carlborg <doob me.com> writes:
On 2013-02-26 22:26, H. S. Teoh wrote:

 I find the Phobos version more readable, actually. Writing "2.days.ago"
 is all neat and clever and everything, but the logician in me protests
 at what all those '.'s are referring to, and they do. Code is not
 English, and when it pretends to be English, it makes me suspicious that
 something is subtle going on that I'm not aware of. And when I'm coding,
 that's something I don't like -- I need to have the assurance I know
 exactly what's going on. And yes I can learn to parse "2.days.ago"
 eventually, but it's just additional mental load for only superficial
 convenience.

I don't agree. BTW, the whole point of having programming languages is for programmers to read and write it. Therefore they are similar to English (or some other language). For the computer the language is just in the way. It just wants to execute machine code.
 IMHO this is just bikeshedding. I actually find Phobos' order more
 intuitive (to me anyway), because the function you're reducing on,
 ideally, should be inlined, so it makes sense to pass it as a
 compile-time parameter, and the seed value is what you start with, so it
 makes sense to have it appear as the first parameter.

I never said it shouldn't be passed as a compile time parameter. Look at the example. I added the seed to the compile time parameter list.
 But I can see where UFCS will fail to kick in here, which makes it a bit
 annoying, I suppose. But reduce was designed before UFCS made it into
 DMD.

Then it should be changed. Oh, wait. We can't break any code, every I don't know why I keep bothering. You (not as in "you" personally) never want to improve anything.
 Couldn't you use map for this purpose?

No, not as far as I know. "map" expects a range and returns a new range. "tap" expects an object and returns the same object. You can use "tap" to tap into chains of method calls and change an object.
 Unfortunately, on this point I have to disagree.

 I find !isBlank much better. Generally, I prefer a more minimal API, but
 I suppose people coming from Ruby might expect a more "rich" kind of API
 design (caveat: I don't know Ruby). Having too many ways of stating the
 same thing makes me wonder if there's some subtle bug lurking somewhere.
 What if isPresent is not 100% equivalent to !isBlank? And I don't mean
 just hypothetically; I've seen cases of libraries where bugs cause two
 supposedly-opposite functions to be not exactly opposite, and then code
 starts to depend on the buggy behaviour, causing hidden bugs later when
 the code gets fixed, etc.. A lot of unnecessary problems when you could
 have just written !isBlank in the first place.

This is not about adding "isPresent" to an already existing "isBlank" this is about adding "isBlank" or "isPresent" which don't exist.
 Now, I used to be a Perl fanatic, so I totally understand TIMTOWTDI and
 all that, but I think having a separate function just to encode !isBlank
 is a bit too extreme.  The language has boolean operators for a reason,
 after all.

isBlank does way more than checking if a value is false or not. Do you read the code at all? -- /Jacob Carlborg
Feb 27 2013
next sibling parent reply Jacob Carlborg <doob me.com> writes:
On 2013-02-27 18:35, H. S. Teoh wrote:


 Not sure who you're referring to here, but the reason reduce probably
 will not change is because a lot of code relies on the current order of
 parameters, and deliberately breaking that just for aesthetic (rather
 than functional) reasons is not a good idea. It would be a different
 story if the current order of parameters somehow makes it impossible to
 implement some particular functionality. I agree that perhaps the
 current situation is not perfect, but at least it's not a complete road
 blocker.

That's the problem. Then we will have a language with a slightly inconsistent and inconvenient standard library.
 Isn't that the same as:

 	map!((obj x) { doSomething(x); return x; })(range)

 ?

 I know it's not as pretty, but at least it's possible.

No it's not the same thing. "map" expects a range and returns a new range. "map" will pass each element from the range to the delegate and then return a new range of all elements returned for each call to the delegate. "tap" on the other hand expects an object or value. It will then pass the object to the delegate and then return the object. Note that it doesn't return whats returned from the delegate. It will always return the object passed to "tap". The most basic, non-templated implementation of "tap" would look like this: Object tap (alias func) (Object o) { func(o); return o; } class Point { int x; int y; } Point createPoint () { return (new Point).tap!((p) { p.x = 3; p.y = 4 }); }
 Again, my point was not that it's a bad idea to have isBlank. My point
 was that if you add isBlank, then isPresent is redundant, and I would
 argue even harmful. The best APIs are minimal ones, that provide all
 *necessary* primitives with minimal overlap between them.

OK, then it was a misunderstanding, my bad. But with this philosophy it will not be as easy create quick scripts compared to scripting languages. This the original question, how to improve that in D. -- /Jacob Carlborg
Feb 27 2013
next sibling parent Jacob Carlborg <doob me.com> writes:
On 2013-02-27 21:12, H. S. Teoh wrote:

 Oh I get it now. So basically it's a wrapper around functions to make
 UFCS chaining possible?

Yes, something like that.
 What would a templated version add to this functionality?

Allow structs to be passed as well. Although they need to be passed by ref. But then you would be able to do this: auto s = Struct(); s.tap!((ref e) { e = Struct(); }); Which should be avoidable if possible.
 I guess I'm skeptical about the value of using tap in this context,
 since you could just call the function on the object, then set its
 values, then return it. So this is just syntactic sugar.

 But I guess I can see some use cases where you're chaining a bunch of
 stuff inside nested function calls, then tap might become convenient:

 	return map!myFunc(zip(r1, [
 		new X().tap!myFunc2(),
 		new X().tap!myFunc2()
 	]));

 Which can be unpacked into linear code, but you would would need a bunch
 of temporary variables to hold the intermediate results.

This is about the little things that makes it convenient to write code. I'm not saying that you cannot do anything without these things. But the question was, what can we do to make D more usable as a scripting language.
 I disagree with this point. Writing !isBlank is just as easy as writing
 isPresent (in fact, a few characters less). I don't see how this helps
 with writing scripts faster.

No, I was more thinking of "The best APIs are minimal ones". If you only have the minimal building blocks you would need to create wrappers and similar to create convenient functions. -- /Jacob Carlborg
Feb 27 2013
prev sibling parent reply Ary Borenszweig <ary esperanto.org.ar> writes:
On 2/27/13 5:12 PM, H. S. Teoh wrote:
 The most basic, non-templated implementation of "tap" would look like
 this:

 Object tap (alias func) (Object o)
 {
      func(o);
      return o;
 }

What would a templated version add to this functionality?
 class Point
 {
      int x;
      int y;
 }

 Point createPoint ()
 {
      return (new Point).tap!((p) { p.x = 3; p.y = 4 });
 }

I guess I'm skeptical about the value of using tap in this context, since you could just call the function on the object, then set its values, then return it. So this is just syntactic sugar.

Tap is nice when you want to print-debug something and you have a chain of calls: auto foo = x.map!(...).reduce!(...).nWayUnion!(...); Now something is not working correctly and you want to see what's after the "reduce!" step: auto foo = x.map!(...).reduce!(...).tap!(r) { writefln(r); }).nWayUnion!(...); Otherwise you'd have to break it in many lines and then put them back together.
Feb 27 2013
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 2/27/13 3:53 PM, Ary Borenszweig wrote:
 Tap is nice when you want to print-debug something and you have a chain
 of calls:

 auto foo = x.map!(...).reduce!(...).nWayUnion!(...);

 Now something is not working correctly and you want to see what's after
 the "reduce!" step:

 auto foo = x.map!(...).reduce!(...).tap!(r) { writefln(r);
 }).nWayUnion!(...);

 Otherwise you'd have to break it in many lines and then put them back
 together.

I like Tap (including the name). It is similar to Unix's "tee" utility. Andrei
Feb 27 2013
parent reply Jacob Carlborg <doob me.com> writes:
On 2013-02-27 22:59, Andrei Alexandrescu wrote:

 I like Tap (including the name). It is similar to Unix's "tee" utility.

Cool, is this something that could be included in Phobos? If yes, where? -- /Jacob Carlborg
Feb 28 2013
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 2/28/13 3:03 AM, Jacob Carlborg wrote:
 On 2013-02-27 22:59, Andrei Alexandrescu wrote:

 I like Tap (including the name). It is similar to Unix's "tee" utility.

Cool, is this something that could be included in Phobos? If yes, where?

I think it belongs to std.range. 1. tap!fun(r) returns a new range (of a new type R1 distinct from typeof(r)). Upon the first call to .front without an intervening popFront, fun(r.front) is called. 2. tap!(fun1, fun2)(r) also returns a new range, calls fun1 as described above, and fun2 whenever popFront() gets called without the front() being looked at. So fun1 tracks the looked-at data and fun2 tracks the ignored data. Andrei
Feb 28 2013
parent reply Jacob Carlborg <doob me.com> writes:
On 2013-02-28 16:18, Andrei Alexandrescu wrote:

 I think it belongs to std.range.

 1. tap!fun(r) returns a new range (of a new type R1 distinct from
 typeof(r)). Upon the first call to .front without an intervening
 popFront, fun(r.front) is called.

 2. tap!(fun1, fun2)(r) also returns a new range, calls fun1 as described
 above, and fun2 whenever popFront() gets called without the front()
 being looked at. So fun1 tracks the looked-at data and fun2 tracks the
 ignored data.

That is not my idea of "tap". This is my idea of "tap": Object (func) (Object o) { func(o); return o; } -- /Jacob Carlborg
Feb 28 2013
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 2/28/13 10:24 AM, Jacob Carlborg wrote:
 On 2013-02-28 16:18, Andrei Alexandrescu wrote:

 I think it belongs to std.range.

 1. tap!fun(r) returns a new range (of a new type R1 distinct from
 typeof(r)). Upon the first call to .front without an intervening
 popFront, fun(r.front) is called.

 2. tap!(fun1, fun2)(r) also returns a new range, calls fun1 as described
 above, and fun2 whenever popFront() gets called without the front()
 being looked at. So fun1 tracks the looked-at data and fun2 tracks the
 ignored data.

That is not my idea of "tap". This is my idea of "tap": Object (func) (Object o) { func(o); return o; }

I know. I think my tap is better than your tap. Andrei
Feb 28 2013
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 2/28/13 10:49 AM, Andrei Alexandrescu wrote:
 On 2/28/13 10:24 AM, Jacob Carlborg wrote:
 On 2013-02-28 16:18, Andrei Alexandrescu wrote:

 I think it belongs to std.range.

 1. tap!fun(r) returns a new range (of a new type R1 distinct from
 typeof(r)). Upon the first call to .front without an intervening
 popFront, fun(r.front) is called.

 2. tap!(fun1, fun2)(r) also returns a new range, calls fun1 as described
 above, and fun2 whenever popFront() gets called without the front()
 being looked at. So fun1 tracks the looked-at data and fun2 tracks the
 ignored data.

That is not my idea of "tap". This is my idea of "tap": Object (func) (Object o) { func(o); return o; }

I know. I think my tap is better than your tap.

... and closer in intent to Ruby's tap as I understand it from reading http://ruby-doc.org/core-2.0/Object.html#method-i-tap No? Andrei
Feb 28 2013
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 2/28/13 11:36 AM, David Nadlinger wrote:
 On Thursday, 28 February 2013 at 15:51:02 UTC, Andrei
 Alexandrescu wrote:
 On 2/28/13 10:49 AM, Andrei Alexandrescu wrote:
 On 2/28/13 10:24 AM, Jacob Carlborg wrote:
 That is not my idea of "tap". This is my idea of "tap":

 Object (func) (Object o)
 {
 func(o);
 return o;
 }

I know. I think my tap is better than your tap.

... and closer in intent to Ruby's tap as I understand it from reading http://ruby-doc.org/core-2.0/Object.html#method-i-tap

Ruby's tap just applies the passed block to the object it is called on. I am not quite sure how your range idea comes into play here? David

Oh, I misunderstood the example at http://ruby-doc.org/core-2.0/Object.html#method-i-tap: (1..10) .tap {|x| puts "original: #{x.inspect}"} .to_a .tap {|x| puts "array: #{x.inspect}"} .select {|x| x%2==0} .tap {|x| puts "evens: #{x.inspect}"} .map { |x| x*x } .tap {|x| puts "squares: #{x.inspect}"} It eagerly prints the entire range, then eagerly prints the entire array, then eagerly the entire filtered range, then eagerly the entire map result. I thought it works lazily, and I think in D it should (otherwise it would be e.g. useless with an input range). So the D translation would be: iota(1, 10) .tap!(a => writeln("original: ", a)) .filter!(a => a % 2 == 0) .tap!(a => writeln("filtered: ", a)) .map!(a => a * a) .tap!(a => writeln("squared: ", a)); This will produce output interleaved, so it's semantically different. I've used something similar to "tap" in a streaming-based library for machine learning I worked on as a grad student. It's been instrumental for data analysis and debugging. This conversation reminded me of it. So my thought on the subject - I don't care much for T tap(alias func)(T x) { func(x); return x; } It's the kind of chaff that doesn't do any real work and only dilutes the value of a library, but I do think a tap tapping into a range does real work and would be a valuable addition. Andrei
Feb 28 2013
next sibling parent Jacob Carlborg <doob me.com> writes:
On 2013-02-28 18:08, Andrei Alexandrescu wrote:

 T tap(alias func)(T x) { func(x); return x; }

 It's the kind of chaff that doesn't do any real work and only dilutes
 the value of a library, but I do think a tap tapping into a range does
 real work and would be a valuable addition.

What about a function allowing both? -- /Jacob Carlborg
Feb 28 2013
prev sibling parent Timon Gehr <timon.gehr gmx.ch> writes:
On 02/28/2013 06:08 PM, Andrei Alexandrescu wrote:
 ...

 So my thought on the subject - I don't care much for

 T tap(alias func)(T x) { func(x); return x; }

I'm not sure who would. template tap(alias func){ T tap(T)(T x){ func(x); return x; } }
 It's the kind of chaff that doesn't do any real work and only dilutes
 the value of a library,  but I do think a tap tapping into a range does
 real work  and would be a valuable addition.
...

map!(tap!func)
Mar 02 2013
prev sibling next sibling parent Jacob Carlborg <doob me.com> writes:
On 2013-02-27 21:01, Rob T wrote:

 I agree.

 I can only see a need for "isPresent" (or the opposite) only if it was
 made clear that isPresent does something different than !isBlank.

 If you continue to use isPresent, then I suggest that it is implemented
 as a convenience wrapper around !isBlank to make sure that changes to
 isBlank automatically propagate back to isPresent.

As I said to H.S. Teoh, the question is not about adding the inverse of an already existing function. It's about adding functionality that doesn't exist. It doesn't matter if isPresent or isBlank would be added. If you had looked at the code you would see the the implementation of isPresent looks like this: property bool isPresent (T) (T t) { return !isBlank(t); } Which is _exactly_ the inverse of isBlank. -- /Jacob Carlborg
Feb 27 2013
prev sibling next sibling parent Jacob Carlborg <doob me.com> writes:
On 2013-02-27 21:07, Rob T wrote:
 On Wednesday, 27 February 2013 at 13:02:02 UTC, Jacob Carlborg wrote:
 [...]
 This is not about adding "isPresent" to an already existing "isBlank"
 this is about adding "isBlank" or "isPresent" which don't exist.

[...]
 isBlank does way more than checking if a value is false or not. Do you
 read the code at all?

This thread got busted up into separate threads over the web interface, so maybe some people (like me) did not read everything you suggested. OK I see you wanted to add only one or the other, not both. I like the idea of having this function in the std.lib. I added it to my own "standard.me" library. --rt PS: The web interface thread splitting is very annoying!

Ok, then my apologize. -- /Jacob Carlborg
Feb 27 2013
prev sibling next sibling parent reply Jacob Carlborg <doob me.com> writes:
On 2013-02-27 21:16, H. S. Teoh wrote:

 This is interesting. I have also been collecting a bunch of stuff that I
 constantly reuse in my own code. I wonder if we should do a survey of
 people's "standard.me" libraries to see what are the functionalities
 most commonly missing from Phobos? That might give us some interesting
 insights into what would be most profitable to add to Phobos.

That's a good idea. This is my library: https://github.com/jacob-carlborg/mambo It's a bit outdated. It started around 2007 with D1 and Tango.
 We *really* need to look into fixing the mailman gateway, which is
 largely the cause of this problem. If I had the power to do it, I would.

I agree. I apologize that I got frustrated in the confusing of threads that were split. -- /Jacob Carlborg
Feb 27 2013
parent Jacob Carlborg <doob me.com> writes:
On 2013-02-28 04:35, Rob T wrote:

 I had a look at your isBlank function. Why not check if length exists
 and run it as follows?

  property bool isBlank (T) (T t)
 {

     static if (__traits(compiles, t.length))
     {
         if (t.length == 0)
            return true;
     }

 ...

 That would be more generic I think.

Sure, I could do that. But I thought checking for "empty" would be more generic. I would expect every type having "length" would/should also have "empty" but perhaps that's a wrong assumption. -- /Jacob Carlborg
Feb 28 2013
prev sibling parent reply Ary Borenszweig <ary esperanto.org.ar> writes:
On 2/27/13 2:35 PM, H. S. Teoh wrote:
 This is not about adding "isPresent" to an already existing "isBlank"
 this is about adding "isBlank" or "isPresent" which don't exist.

My point was that you only need one of them, not both. I don't see what's the advantage of adding both isBlank and isPresent, when adding just one will already give you the functionality of the other. I didn't mean to say that it's a bad idea to add *either* one.

Then why not remove the binary "-" from D. You can always do: a + -b I believe this makes the language simpler.
Feb 27 2013
parent "Daniel Murphy" <yebblies nospamgmail.com> writes:
"Ary Borenszweig" <ary esperanto.org.ar> wrote in message 
news:512E717B.7090808 esperanto.org.ar...
 Then why not remove the binary "-" from D. You can always do:

 a + -b

 I believe this makes the language simpler.

Compatibility with C.
Mar 01 2013
prev sibling next sibling parent "Rob T" <alanb ucora.com> writes:
On Wednesday, 27 February 2013 at 13:02:02 UTC, Jacob Carlborg 
wrote:
[...]
 This is not about adding "isPresent" to an already existing 
 "isBlank" this is about adding "isBlank" or "isPresent" which 
 don't exist.

[...]
 isBlank does way more than checking if a value is false or not. 
 Do you read the code at all?

This thread got busted up into separate threads over the web interface, so maybe some people (like me) did not read everything you suggested. OK I see you wanted to add only one or the other, not both. I like the idea of having this function in the std.lib. I added it to my own "standard.me" library. --rt PS: The web interface thread splitting is very annoying!
Feb 27 2013
prev sibling next sibling parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Wed, Feb 27, 2013 at 09:07:15PM +0100, Rob T wrote:
 On Wednesday, 27 February 2013 at 13:02:02 UTC, Jacob Carlborg
 wrote:
 [...]
This is not about adding "isPresent" to an already existing
"isBlank" this is about adding "isBlank" or "isPresent" which
don't exist.

isBlank does way more than checking if a value is false or not. Do
you read the code at all?

This thread got busted up into separate threads over the web interface, so maybe some people (like me) did not read everything you suggested. OK I see you wanted to add only one or the other, not both. I like the idea of having this function in the std.lib. I added it to my own "standard.me" library.

This is interesting. I have also been collecting a bunch of stuff that I constantly reuse in my own code. I wonder if we should do a survey of people's "standard.me" libraries to see what are the functionalities most commonly missing from Phobos? That might give us some interesting insights into what would be most profitable to add to Phobos. Having said that, though, I found that my D personal library is much smaller than my C/C++ one, mostly because Phobos already covered a large part of that functionality! So Phobos is doing *something* right, in spite of all its current flaws. [...]
 PS: The web interface thread splitting is very annoying!

We *really* need to look into fixing the mailman gateway, which is largely the cause of this problem. If I had the power to do it, I would. T -- Microsoft is to operating systems & security ... what McDonalds is to gourmet cooking.
Feb 27 2013
prev sibling next sibling parent "Rob T" <alanb ucora.com> writes:
On Wednesday, 27 February 2013 at 20:18:29 UTC, H. S. Teoh wrote:
[...]
 Having said that, though, I found that my D personal library is 
 much
 smaller than my C/C++ one, mostly because Phobos already 
 covered a large
 part of that functionality! So Phobos is doing *something* 
 right, in
 spite of all its current flaws.

I also found that my D version of my std.me lib is a lot smaller than the C++ version, so Phobos seems to do a lot more than the C++ std lib does, and what I've used so far seems to be well done. I've only managed to scratch the surface though. I think with C++ you have to use boost to get the same as what you get with Phobos, but I never liked working with boost. --rt
Feb 27 2013
prev sibling next sibling parent "Rob T" <alanb ucora.com> writes:
On Wednesday, 27 February 2013 at 20:43:47 UTC, Jacob Carlborg 
wrote:
 That's a good idea. This is my library:

 https://github.com/jacob-carlborg/mambo

 It's a bit outdated. It started around 2007 with D1 and Tango.

I had a look at your isBlank function. Why not check if length exists and run it as follows? property bool isBlank (T) (T t) { static if (__traits(compiles, t.length)) { if (t.length == 0) return true; } ... That would be more generic I think. --rt
Feb 27 2013
prev sibling next sibling parent "Rob T" <alanb ucora.com> writes:
On Wednesday, 27 February 2013 at 20:18:29 UTC, H. S. Teoh wrote:
 I wonder if we should do a survey of
 people's "standard.me" libraries to see what are the 
 functionalities
 most commonly missing from Phobos? That might give us some 
 interesting
 insights into what would be most profitable to add to Phobos.

Once we get ability to add user comments to Phobos documentation, then maybe that will help determine what is working and what is not, and also what is missing that perhaps should be there. --rt
Feb 27 2013
prev sibling next sibling parent "deadalnix" <deadalnix gmail.com> writes:
On Thursday, 28 February 2013 at 08:05:20 UTC, Jacob Carlborg 
wrote:
 On 2013-02-28 04:35, Rob T wrote:

 I had a look at your isBlank function. Why not check if length 
 exists
 and run it as follows?

  property bool isBlank (T) (T t)
 {

    static if (__traits(compiles, t.length))
    {
        if (t.length == 0)
           return true;
    }

 ...

 That would be more generic I think.

Sure, I could do that. But I thought checking for "empty" would be more generic. I would expect every type having "length" would/should also have "empty" but perhaps that's a wrong assumption.

It is easy to ensure via UFCS.
Feb 28 2013
prev sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Thursday, February 28, 2013 09:05:19 Jacob Carlborg wrote:
 On 2013-02-28 04:35, Rob T wrote:
 I had a look at your isBlank function. Why not check if length exists
 and run it as follows?
 
  property bool isBlank (T) (T t)
 {
 
     static if (__traits(compiles, t.length))
     {
     
         if (t.length == 0)
         
            return true;
     
     }
 
 ...
 
 That would be more generic I think.

Sure, I could do that. But I thought checking for "empty" would be more generic. I would expect every type having "length" would/should also have "empty" but perhaps that's a wrong assumption.

All ranges are guaranteed to have empty, so any range with length will obviously have empty. Regardless, in general, it's better to check for empty than length, since it's possible for empty to be more efficient, and it's unlikely the empty will ever be less efficient than checking that length == 0. If you're not talking about ranges, then all bets are off as to what it does and doesn't have, because that would depend on what APIs it adheres to and what they're like. - Jonathan M Davis
Feb 28 2013