www.digitalmars.com         C & C++   DMDScript  

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

reply "Craig Dillabaugh" <cdillaba cg.scs.carleton.ca> writes:
I am a novice D programmer and use C++ in my work. One thing I
find myself doing when I need to implement some non-trivial
algorithm is that I will originally code it in D and perform
testing from there to make sure I have the logic right.
Once I have everything working in D I simply port it over to C++.

In my experience this porting is very trivial (it probably helps
there that I write D like a C++ programmer). While I don't have
hard evidence I think that the 'porting' effort to C++ is more
than offset by the productivity gains I achieve fighting with C++
syntax while trying to get the logic right. Most of the porting
effort is simply copying and pasting the D code into my C++
source files and adding headers, replacing imports with includes,
etc. Usually significant portions of the code compile without any
changes.

I was curious to know if anyone else uses D like this. If so this
might be a good way to try and get D into some C++ shops.  The
nice thing about D in my opinion is that even for people without
D experience, if they have C++ experience they can likely 'read'
D code without much trouble (of course some features might not
map over so well - but the languages are syntactically very
close).
Feb 26 2013
next sibling parent reply dennis luehring <dl.soluz gmx.net> writes:
Am 26.02.2013 16:26, schrieb Craig Dillabaugh:
 I am a novice D programmer and use C++ in my work. One thing I
 find myself doing when I need to implement some non-trivial
 algorithm is that I will originally code it in D and perform
 testing from there to make sure I have the logic right.
 Once I have everything working in D I simply port it over to C++.

i don't get it you are an novice D programmer and your programs are easy to convert back to C++ so you'r not using too much D specials whats the point of doing it like this?
Feb 26 2013
next sibling parent "Namespace" <rswhite4 googlemail.com> writes:
On Tuesday, 26 February 2013 at 15:43:42 UTC, dennis luehring 
wrote:
 Am 26.02.2013 16:26, schrieb Craig Dillabaugh:
 I am a novice D programmer and use C++ in my work. One thing I
 find myself doing when I need to implement some non-trivial
 algorithm is that I will originally code it in D and perform
 testing from there to make sure I have the logic right.
 Once I have everything working in D I simply port it over to 
 C++.

i don't get it you are an novice D programmer and your programs are easy to convert back to C++ so you'r not using too much D specials whats the point of doing it like this?

I do it as well. In D you can write code (mostly) much faster. However, I would not attempt to implement larger projects (more) in D, because D is simply not mature enough and lacks too much. So after writing and testing in D, I port my program/code then in C++ and complete it.
Feb 26 2013
prev sibling next sibling parent "monarch_dodra" <monarchdodra gmail.com> writes:
On Tuesday, 26 February 2013 at 15:43:42 UTC, dennis luehring 
wrote:
 Am 26.02.2013 16:26, schrieb Craig Dillabaugh:
 I am a novice D programmer and use C++ in my work. One thing I
 find myself doing when I need to implement some non-trivial
 algorithm is that I will originally code it in D and perform
 testing from there to make sure I have the logic right.
 Once I have everything working in D I simply port it over to 
 C++.

i don't get it you are an novice D programmer and your programs are easy to convert back to C++ so you'r not using too much D specials whats the point of doing it like this?

It's not about using special features. As a matter of fact, I'd think he'd purposefully stay away from special features. The point is that he *develop* the program in D in half the time it would have taken him in C++. Given this productivity gain, he can mess and improve his program much faster and with more quality than he could have in C++. Once his D program is stable and the outline/flow is clearer to him, and he knows what he wants to do, he only has to convert to C++, which can be done very fast. I do this too. It is *very* helpful when you don't know *where* you are going when you start. I'd stick to D all the way, but as namespace said, D may not be mature enough, or stable enough, or just allowed as a final language in the workplace :/
Feb 26 2013
prev sibling parent "Craig Dillabaugh" <cdillaba cg.scs.carleton.ca> writes:
On Tuesday, 26 February 2013 at 15:43:42 UTC, dennis luehring
wrote:
 Am 26.02.2013 16:26, schrieb Craig Dillabaugh:
 I am a novice D programmer and use C++ in my work. One thing I
 find myself doing when I need to implement some non-trivial
 algorithm is that I will originally code it in D and perform
 testing from there to make sure I have the logic right.
 Once I have everything working in D I simply port it over to 
 C++.

i don't get it you are an novice D programmer and your programs are easy to convert back to C++ so you'r not using too much D specials whats the point of doing it like this?

I should qualify that a bit. I don't avoid D features altogether, but I don't necessarily use many of the advanced features (eg. mixins) that might have no equivalent in C++. I work in scientific computing so I do much of my work with arrays. Working with D arrays is much, much nicer than in C++. So I save lots of time getting my algorithm working/tested. Then the porting is pretty simple, because while slices for example are not supported in C++ you can handle the same logic in C++ without too much trouble. However, the C++ code is uglier and not having to deal with that ugliness lets me focus my mental effort on the details of my algorithm. This lets me implement it correctly more quickly. Using D associative arrays vs C++ std.map is another example. Now, I would never suggest using D to prototype a full application or anything like that, but at least for the type of work I tend to do I find that using D lets me focus on my 'algorithm' without fight with awkward syntax.
Feb 26 2013
prev sibling next sibling parent reply "bearophile" <bearophileHUGS lycos.com> writes:
Craig Dillabaugh:

 I am a novice D programmer and use C++ in my work. One thing I
 find myself doing when I need to implement some non-trivial
 algorithm is that I will originally code it in D and perform
 testing from there to make sure I have the logic right.
 Once I have everything working in D I simply port it over to 
 C++.

I often write the code in D (sometimes I start from Python and then I convert it to D), get it right, write down more tests, then I slowly lower the level of the D code keeping it correct with help of the tests, and then convert it to C. When the code is quite complex, if I do this I waste some time, but it's a known amount of time, while if I follow a more direct route, writing the C code directly, I can't tell how much debugging time I will need. Bye, bearophile
Feb 26 2013
parent "Craig Dillabaugh" <cdillaba cg.scs.carleton.ca> writes:
On Tuesday, 26 February 2013 at 16:15:49 UTC, bearophile wrote:
 Craig Dillabaugh:

 I am a novice D programmer and use C++ in my work. One thing I
 find myself doing when I need to implement some non-trivial
 algorithm is that I will originally code it in D and perform
 testing from there to make sure I have the logic right.
 Once I have everything working in D I simply port it over to 
 C++.

I often write the code in D (sometimes I start from Python and then I convert it to D), get it right, write down more tests, then I slowly lower the level of the D code keeping it correct with help of the tests, and then convert it to C. When the code is quite complex, if I do this I waste some time, but it's a known amount of time, while if I follow a more direct route, writing the C code directly, I can't tell how much debugging time I will need. Bye, bearophile

One of the reasons I like D for this kind of work is that as a multi-paradigm language it lets you do stuff in a style closer what your final C++ code will look like. My research is in satellite image processing, so most of my work involves reading in imagery into 2D arrays and performing processing over all/or part of an image. I find being able to write code like: for(int i =0; i < rows; i++) { for(int j = 0; j < cols; j++) { } } Sometimes is the easiest way to perform certain tasks. D lets you do this and the syntax is exactly the same a C/C++ - Python? I don't know - but I imagine it would be tricker to port to C++! I have found, at least in this particular problem domain, that the C++/D style syntax is about as good as it gets.
Feb 26 2013
prev sibling next sibling parent reply "renoX" <renozyx gmail.com> writes:
On Tuesday, 26 February 2013 at 15:26:17 UTC, Craig Dillabaugh 
wrote:
 I am a novice D programmer and use C++ in my work. One thing I
 find myself doing when I need to implement some non-trivial
 algorithm is that I will originally code it in D and perform
 testing from there to make sure I have the logic right.
 Once I have everything working in D I simply port it over to 
 C++.

I'm curious: is this process still useful with C++11? BR, renoX
Feb 26 2013
parent reply "Craig Dillabaugh" <cdillaba cg.scs.carleton.ca> writes:
On Tuesday, 26 February 2013 at 16:34:01 UTC, renoX wrote:
 On Tuesday, 26 February 2013 at 15:26:17 UTC, Craig Dillabaugh 
 wrote:
 I am a novice D programmer and use C++ in my work. One thing I
 find myself doing when I need to implement some non-trivial
 algorithm is that I will originally code it in D and perform
 testing from there to make sure I have the logic right.
 Once I have everything working in D I simply port it over to 
 C++.

I'm curious: is this process still useful with C++11? BR, renoX

Again since my work is heavily array based probably, I would guess so, but perhaps not quite so much. How long though until C++11 is broadly available?
Feb 26 2013
parent "monarch_dodra" <monarchdodra gmail.com> writes:
On Tuesday, 26 February 2013 at 16:34:01 UTC, renoX wrote:
 On Tuesday, 26 February 2013 at 15:26:17 UTC, Craig Dillabaugh 
 wrote:
 I am a novice D programmer and use C++ in my work. One thing I
 find myself doing when I need to implement some non-trivial
 algorithm is that I will originally code it in D and perform
 testing from there to make sure I have the logic right.
 Once I have everything working in D I simply port it over to 
 C++.

I'm curious: is this process still useful with C++11? BR, renoX

Have you tried it? C++11 can prototype faster than C++, but it ain't D. On Tuesday, 26 February 2013 at 16:55:50 UTC, Craig Dillabaugh wrote:
 On Tuesday, 26 February 2013 at 16:34:01 UTC, renoX wrote:
 On Tuesday, 26 February 2013 at 15:26:17 UTC, Craig Dillabaugh 
 wrote:
 I am a novice D programmer and use C++ in my work. One thing I
 find myself doing when I need to implement some non-trivial
 algorithm is that I will originally code it in D and perform
 testing from there to make sure I have the logic right.
 Once I have everything working in D I simply port it over to 
 C++.

I'm curious: is this process still useful with C++11? BR, renoX

Again since my work is heavily array based probably, I would guess so, but perhaps not quite so much. How long though until C++11 is broadly available?

AFAIK, it's already mostly available from both GCC and VS. *Some* functionality is still missing, but nothing major.
Feb 26 2013
prev sibling next sibling parent reply "MattCodr" <matheus_nab hotmail.com> writes:
On Tuesday, 26 February 2013 at 15:26:17 UTC, Craig Dillabaugh
wrote:
 I was curious to know if anyone else uses D like this.

I usually do this, but in a little different way. I wrote my code in a interpreted language, and then I port to D or C languages.
Feb 26 2013
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 2/26/13 11:46 AM, MattCodr wrote:
 On Tuesday, 26 February 2013 at 15:26:17 UTC, Craig Dillabaugh
 wrote:
 I was curious to know if anyone else uses D like this.

I usually do this, but in a little different way. I wrote my code in a interpreted language, and then I port to D or C languages.

These are great data points. We should figure how to improve D to lessen the barriers in both directions. Andrei
Feb 26 2013
next sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
Andrei Alexandrescu:

 We should figure how to improve D to lessen the barriers in 
 both directions.

Regarding the D => C conversions I write, time ago I have suggested a "-cstyle" compiler switch: http://d.puremagic.com/issues/show_bug.cgi?id=4580 Bye, bearophile
Feb 26 2013
prev sibling next sibling parent reply Jacob Carlborg <doob me.com> writes:
On 2013-02-26 18:45, Andrei Alexandrescu wrote:

 These are great data points. We should figure how to improve D to lessen
 the barriers in both directions.

It helps by having convenient functions in the standard library. It also helps with not having to import a lot of modules just to get something simple done. I don't know if it's that I'm not so used to Phobos but it doesn't feel as intuitive to work with in comparison with say Ruby. In particular with Rails which adds a lot of convenient functions. -- /Jacob Carlborg
Feb 26 2013
parent reply "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Tue, Feb 26, 2013 at 08:49:12PM +0100, Jacob Carlborg wrote:
 On 2013-02-26 18:45, Andrei Alexandrescu wrote:
 
These are great data points. We should figure how to improve D to
lessen the barriers in both directions.

It helps by having convenient functions in the standard library. It also helps with not having to import a lot of modules just to get something simple done. I don't know if it's that I'm not so used to Phobos but it doesn't feel as intuitive to work with in comparison with say Ruby. In particular with Rails which adds a lot of convenient functions.

[...] Do you have any specific examples? T -- Study gravitation, it's a field with a lot of potential.
Feb 26 2013
next sibling parent reply Jacob Carlborg <doob me.com> writes:
On 2013-02-26 20:52, H. S. Teoh wrote:

 Do you have any specific examples?

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 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) * No algorithm functions for associative arrays. * 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; }); } This becomes a bit tricky because we want structs to be passed by ref, but preferably we don't want to be able to change the parameter in the delegate. In Ruby it's no problem since all types are reference types. I probably can come up with more later. -- /Jacob Carlborg
Feb 26 2013
next sibling parent reply Ary Borenszweig <ary esperanto.org.ar> writes:
On 2/26/13 6:01 PM, Jacob Carlborg wrote:
 On 2013-02-26 20:52, H. S. Teoh wrote:

 Do you have any specific examples?

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 think it's mostly std.algorithm that is the problem.

And also having to import std.algorithm. In Ruby you can do map, sort and whatever without using an import. You use it so often that an import is annoying.
Feb 26 2013
next sibling parent "simendsjo" <simendsjo gmail.com> writes:
On Tuesday, 26 February 2013 at 21:10:30 UTC, Ary Borenszweig 
wrote:
 On 2/26/13 6:01 PM, Jacob Carlborg wrote:
 On 2013-02-26 20:52, H. S. Teoh wrote:

 Do you have any specific examples?

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 think it's mostly std.algorithm that is the problem.

And also having to import std.algorithm. In Ruby you can do map, sort and whatever without using an import. You use it so often that an import is annoying.

I often find myself importing std.algorithm, std.array and std.range even for the simplest things. std.string, std.ascii, std.conv, std.stdio is also quite common at the top of my files.. And *then* I import modules more specific for the problem I'm going to solve :) I sometimes wish I was using an editor that automatically added the imports for me.
Feb 26 2013
prev sibling parent Jacob Carlborg <doob me.com> writes:
On 2013-02-26 22:10, Ary Borenszweig wrote:

 And also having to import std.algorithm. In Ruby you can do map, sort
 and whatever without using an import. You use it so often that an import
 is annoying.

Often you need std.range and std.array as well. -- /Jacob Carlborg
Feb 27 2013
prev sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 2/26/13 4:01 PM, Jacob Carlborg wrote:
 On 2013-02-26 20:52, H. S. Teoh wrote:

 Do you have any specific examples?

Return the date from two days ago: Ruby on Rails: 2.days.ago Date.today Time.now

The last two return the time right now, how come? Andrei
Feb 26 2013
parent Jacob Carlborg <doob me.com> writes:
On 2013-02-27 00:39, Andrei Alexandrescu wrote:

 The last two return the time right now, how come?

They're supposed to. I just accidentally put them below "Return the date from two days ago". -- /Jacob Carlborg
Feb 27 2013
prev sibling parent Jacob Carlborg <doob me.com> writes:
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 -- /Jacob Carlborg
Feb 26 2013
prev sibling parent reply Paulo Pinto <pjmlp progtools.org> writes:
On 26.02.2013 18:45, Andrei Alexandrescu wrote:
 On 2/26/13 11:46 AM, MattCodr wrote:
 On Tuesday, 26 February 2013 at 15:26:17 UTC, Craig Dillabaugh
 wrote:
 I was curious to know if anyone else uses D like this.

I usually do this, but in a little different way. I wrote my code in a interpreted language, and then I port to D or C languages.

These are great data points. We should figure how to improve D to lessen the barriers in both directions. Andrei

REPL?
Feb 27 2013
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 2/27/13 3:29 AM, Paulo Pinto wrote:
 On 26.02.2013 18:45, Andrei Alexandrescu wrote:
 On 2/26/13 11:46 AM, MattCodr wrote:
 On Tuesday, 26 February 2013 at 15:26:17 UTC, Craig Dillabaugh
 wrote:
 I was curious to know if anyone else uses D like this.

I usually do this, but in a little different way. I wrote my code in a interpreted language, and then I port to D or C languages.

These are great data points. We should figure how to improve D to lessen the barriers in both directions. Andrei

REPL?

Good idea. Should be in bugzilla as an enh, although it'll take a while to get to that. Andrei
Feb 27 2013
next sibling parent "Zach the Mystic" <reachBUTMINUSTHISzach gOOGLYmail.com> writes:
On Wednesday, 27 February 2013 at 10:07:43 UTC, Andrei 
Alexandrescu wrote:
 On 2/27/13 3:29 AM, Paulo Pinto wrote:
 On 26.02.2013 18:45, Andrei Alexandrescu wrote:
 On 2/26/13 11:46 AM, MattCodr wrote:
 On Tuesday, 26 February 2013 at 15:26:17 UTC, Craig 
 Dillabaugh
 wrote:
 I was curious to know if anyone else uses D like this.

I usually do this, but in a little different way. I wrote my code in a interpreted language, and then I port to D or C languages.

These are great data points. We should figure how to improve D to lessen the barriers in both directions. Andrei

REPL?

Good idea. Should be in bugzilla as an enh, although it'll take a while to get to that. Andrei

D would be one step closer to actually passing the "BOTCH" test! http://mathprogrammer.com/blog/?p=12
Feb 27 2013
prev sibling parent reply Jacob Carlborg <doob me.com> writes:
On 2013-02-27 11:07, Andrei Alexandrescu wrote:

 Good idea. Should be in bugzilla as an enh, although it'll take a while
 to get to that.

I wonder how good the implementation will be if one just pass the line to rdmd and prints the result. -- /Jacob Carlborg
Feb 27 2013
next sibling parent "timotheecour" <thelastmammoth gmail.com> writes:
On Wednesday, 27 February 2013 at 19:55:41 UTC, Jacob Carlborg 
wrote:
 On 2013-02-27 11:07, Andrei Alexandrescu wrote:

 Good idea. Should be in bugzilla as an enh, although it'll 
 take a while
 to get to that.

I wonder how good the implementation will be if one just pass the line to rdmd and prints the result.

I'm assuming you're talking about REPL. That won't cut it, as one wants to keep maintain a notion of state (variables in memory etc) and not reparse lines entered everytime (which could have IO side effects etc). I've played a bit with Oskar Linde's library for that and ported it to latest DMD release and it works quite well already, something solid to build upon (see post http://forum.dlang.org/thread/fpmpa6$2muq$1 digitalmars.com).
Feb 27 2013
prev sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 2/27/13 2:55 PM, Jacob Carlborg wrote:
 On 2013-02-27 11:07, Andrei Alexandrescu wrote:

 Good idea. Should be in bugzilla as an enh, although it'll take a while
 to get to that.

I wonder how good the implementation will be if one just pass the line to rdmd and prints the result.

Try it, rdmd has --eval and --loop. It's useful but not as good as a real REPL. Andrei
Feb 27 2013
parent Jacob Carlborg <doob me.com> writes:
On 2013-02-27 22:54, Andrei Alexandrescu wrote:

 Try it, rdmd has --eval and --loop. It's useful but not as good as a
 real REPL.

I'll give that a try, thanks. -- /Jacob Carlborg
Feb 27 2013
prev sibling next sibling parent Joseph Rushton Wakeling <joseph.wakeling webdrake.net> writes:
On 02/26/2013 04:26 PM, Craig Dillabaugh wrote:
 I am a novice D programmer and use C++ in my work. One thing I
 find myself doing when I need to implement some non-trivial
 algorithm is that I will originally code it in D and perform
 testing from there to make sure I have the logic right.
 Once I have everything working in D I simply port it over to C++.

I have to say that these days (also as someone who programs for scientific research purposes) I find that I can both write _and_ use D effectively -- the range of functionality that I need to rely on is pretty solid in D. Depending on exactly what it is you need to use, your sense of the "maturity" of D may be paranoid (but of course I appreciate paranoia as a virtue where scientific software is concerned:-). Now, that said, I can see myself doing exactly what you describe in a case where I really felt the need to use C/C++. The major reason to do so would probably be ease of access to C or C++ libraries, or collaborative requirements (most of my colleagues are C++ users for serious number crunching, although at least one typically uses FORTRAN).
Feb 26 2013
prev sibling next sibling parent 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 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 "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Wed, Feb 27, 2013 at 02:02:01PM +0100, Jacob Carlborg wrote:
 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.

OK, then let's agree to disagree. I see that there's no point in arguing about this, since it ultimately comes down to preference, which can never be reconciled.
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.

Yes, I was just talking about the order of parameters.
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.

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.
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.

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.
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.

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.
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?

[...] 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. T -- Who told you to swim in Crocodile Lake without life insurance??
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
parent reply "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Wed, Feb 27, 2013 at 08:54:21PM +0100, Jacob Carlborg wrote:
 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.

Well, given that we have UFCS now, maybe we *do* want to standardize on the range always being the first argument, so that UFCS chaining always works. I'm OK to have reduce change the order of arguments... but given the amount of code it will break, I doubt it will get in. One way is to introduce the new version under a different name and deprecate "reduce". I'm not the person you have to convince, though; it's Jonathan or Andrei who will decide whether to accept this change.
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".

Oh I get it now. So basically it's a wrapper around functions to make UFCS chaining possible?
 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. 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.
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.

[...] 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. T -- Answer: Because it breaks the logical sequence of discussion. / Question: Why is top posting bad?
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 "David Nadlinger" <see klickverbot.at> writes:
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
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 reply "Rob T" <alanb ucora.com> writes:
On Wednesday, 27 February 2013 at 17:37:34 UTC, H. S. Teoh wrote:
[...]
 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.


 T

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. --rt
Feb 27 2013
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 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 parent reply "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
next sibling parent reply "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
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 reply "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
parent reply 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
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
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 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 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 "Rob T" <alanb ucora.com> writes:
On Tuesday, 26 February 2013 at 15:26:17 UTC, Craig Dillabaugh 
wrote:
 I am a novice D programmer and use C++ in my work. One thing I
 find myself doing when I need to implement some non-trivial
 algorithm is that I will originally code it in D and perform
 testing from there to make sure I have the logic right.
 Once I have everything working in D I simply port it over to 
 C++.

 In my experience this porting is very trivial (it probably helps
 there that I write D like a C++ programmer). While I don't have
 hard evidence I think that the 'porting' effort to C++ is more
 than offset by the productivity gains I achieve fighting with 
 C++
 syntax while trying to get the logic right. Most of the porting
 effort is simply copying and pasting the D code into my C++
 source files and adding headers, replacing imports with 
 includes,
 etc. Usually significant portions of the code compile without 
 any
 changes.

 I was curious to know if anyone else uses D like this. If so 
 this
 might be a good way to try and get D into some C++ shops.  The
 nice thing about D in my opinion is that even for people without
 D experience, if they have C++ experience they can likely 'read'
 D code without much trouble (of course some features might not
 map over so well - but the languages are syntactically very
 close).

I can understand why you are doing this. C++ code tends to be about 3x the volume of well written D code, so a lot of effort is wasted when coding in C++, so if you can get it right through using D, then translate to C++, you'll save a lot of time, but of course we're better off using D directly, but first the language and tool set has to be made production use ready. Once full shared library support comes about, we'll be able to integrate D libs directly into existing C/C++ code. This allows for a safe migration path away from legacy C/C++ to D. --rt
Feb 26 2013
parent reply "monarch_dodra" <monarchdodra gmail.com> writes:
On Tuesday, 26 February 2013 at 23:46:52 UTC, Rob T wrote:
 Once full shared library support comes about, we'll be able to 
 integrate D libs directly into existing C/C++ code. This allows 
 for a safe migration path away from legacy C/C++ to D.

 --rt

Funny story, I'm doing it the other way around. I got my program fully working in D, and am porting it to C. The basic idea is that I'm going to port it "chunk by chunk" to C, while keeping my main in D. This allows me to "package" the finished parts in C, but still work on the rest in D. It also means the porting doesn't have to be done in its totality in a single pass.
Feb 27 2013
parent "Rob T" <alanb ucora.com> writes:
On Wednesday, 27 February 2013 at 08:30:18 UTC, monarch_dodra 
wrote:
 On Tuesday, 26 February 2013 at 23:46:52 UTC, Rob T wrote:
 Once full shared library support comes about, we'll be able to 
 integrate D libs directly into existing C/C++ code. This 
 allows for a safe migration path away from legacy C/C++ to D.

 --rt

Funny story, I'm doing it the other way around. I got my program fully working in D, and am porting it to C. The basic idea is that I'm going to port it "chunk by chunk" to C, while keeping my main in D. This allows me to "package" the finished parts in C, but still work on the rest in D. It also means the porting doesn't have to be done in its totality in a single pass.

I understand why your are doing this, but it must be a ton of work, and has a lot of potential for introducing bugs that do not exist in the D code base. Someone proposed that we compile D to JVM bytecode, but maybe we should have D compile to C or C++ source code instead, at least that can work fully unlike with JVM bytecode, and it would save you guys a lot of work --rt
Feb 27 2013
prev sibling parent reply "simendsjo" <simendsjo gmail.com> writes:
On Tuesday, 26 February 2013 at 15:26:17 UTC, Craig Dillabaugh 
wrote:
 I am a novice D programmer and use C++ in my work. One thing I
 find myself doing when I need to implement some non-trivial
 algorithm is that I will originally code it in D and perform
 testing from there to make sure I have the logic right.
 Once I have everything working in D I simply port it over to 
 C++.

(...) I'm surprised to see many people doing this. But I'm wondering.. If you already got the code working in D, why not let it stay there and write a C interface? Company policy? Missing dynamic loading? Some build issues? If the code could stay in D, it would seem like a good way to slowly integrate D into a company.
Feb 27 2013
parent "Namespace" <rswhite4 googlemail.com> writes:
 I'm surprised to see many people doing this. But I'm wondering..
 If you already got the code working in D, why not let it stay 
 there and write a C interface?
 Company policy? Missing dynamic loading? Some build issues?

 If the code could stay in D, it would seem like a good way to 
 slowly integrate D into a company.

As we said: D isn't mature enough. As long as your code base isn't too complex, D is very nice but at some point you get many stumbling blocks, bugs or missing features which is very annoying. I like D, but it is far away from using it instead of C++.
Feb 27 2013