tools
                                
                                
                                
                                    tools copied to clipboard
                            
                            
                            
                        rdmd: and with a last statement without effect should print it
tl;dr: @WebDrake recently changed the rdmd to automatically add semicolons for the last statement without effect (https://github.com/dlang/tools/pull/303), but I think we can do a bit better and make rdmd even more user-friendly.
At the moment we are in the unique position to introduce this without any breakage as until now rdmd didn't allow this:
> rdmd --eval='"hello"'
/tmp/.rdmd-1000/eval.CFD785092747553A81673B51A318D6AE.d(18): Error: "hello" has no effect
The new behavior will default to writeln if the last statement would have no effect:
> rdmd --eval="hello"
hello
A few more examples:
$(H4 Use rdmd as your calculator)
> rdmd --eval="2 + 2"
4
> rdmd --loop='line.splitter(",").take(1)'
16
> seq 5 | rdmd --loop='stdin.byLine.drop(2).joiner(newline)'
2
3
4
5
...
I'm aware that this is a "poor man's solution" and could be done better, but look at it this way:
- it doesn't break any code
 - it's a 6 LoC change (imports and tests not counted)
 - it covers >95% of all uses
 - it increases the user-friendliness of 
rdmdand people who use it likeperl's eval 
Q: Oh come on, people can just type writeln themselves
Yes of course, but for CLI tools every keystroke matters and REPLs print to stdout. Also it's a nice default for these two specific flags (in comparison to the hard error).
CC @CyberShadow @marler8997 @WebDrake @andralex
Thanks for your pull request, @wilzbach!
Bugzilla references
Your PR doesn't reference any Bugzilla issue.
If your PR contains non-trivial changes, please reference a Bugzilla issue or create a manual changelog.
This is nice if we manage to make it unambiguous.
One thought comes to mind, would we need to support the case where a developer doesn't want the return value of their expression to be printed?
One thought comes to mind, would we need to support the case where a developer doesn't want the return value of their expression to be printed?
Then he can add a semi-colon (as before).
Try a test with "if(0) {} 2 + 2" - that won't work
It would error too at the moment - but sure that's easy enough. Well, at the moment the logic is super simple and there are these pendantic examples of e.g.
"foo" ~ ";" ~ "bar"
The point was that everything without an ending semi-color fails atm and this trick will do the sensible thing in the vast majority of cases. If this isn't acceptable, I can also look into a minimal tokenizer for expressions, but that would require a lot more effort.
Let's at least partially revert #303, s.t. we aren't limited by it for the future direction of this PR (-> https://github.com/dlang/tools/pull/318).
tl;dr: @WebDrake recently changed the rdmd to automatically add semicolons for the last statement without effect (#303)
For the record (we've already discussed this in other PRs): no, I didn't.
Automatically adding closing semicolons to code provided via --eval has been there since the flag was first introduced in commit b08b87e88bd94569b6e88376d79aeb6753b11fff (back in 2009).
What #303 changed was to stop that closing semicolon being added if one was already there (to avoid empty statements at the end of the program, which some compilers object to).
BTW, I would like to understand better the particular motivation behind this feature, other than that it seems cool. "95% of all uses" are mentioned above. What are those uses? Are they motivated by real, reported user needs? Or just imagination about what users might do?
"people who use it like perl's eval" are mentioned, but AFAICT, perl -e doesn't do anything like this.  perl -e '"Hello World!\n"' gives you no output, for example; you have to explicitly use print.
I ask all this because it seems an odd thing to magically special case the behaviour of D code for this one specific use-case.
The good old principle of least surprise suggests that --eval should evaluate the D code you give it, no more, no less.  I'm not sure it's wise to second-guess our users by magically giving them different behaviour from that, for a very narrow subset of the possible code that could be provided.
Could you provide examples you would find surprising?
Could you provide examples you would find surprising?
If I ask for a piece of D code to be evaluated, I expect for that D code to be evaluated as it is. I do not expect for some extra magic to be done that prints out something I didn't ask to be printed.
I certainly do not expect the difference between nothing happening versus something happening to be whether or not I put a semicolon on the end of the code I provided. That's really weird special-casing.
In a case like this, the onus really has to be on the feature proposal to explain what is so good and valuable about it that we need to break with the intuitive and longstanding behaviour of --eval.
--eval is going to be easiest to understand and use if it just treats the D code it's given like any other D code.  Which (apart from adding trailing semicolons, which is just about tolerable as a helping hand) is what it's always done.
Most of that was just repeating what you already said...
You said it would be surprising, can you provide surprising examples you were thinking of so the rest of us can evaluate it for ourselves? Surprise is subjective after all
NO. This is fundamentally the wrong way to be thinking about this.
--eval is a feature which has been part of rdmd, virtually unchanged (apart from bugfixes) for almost 10 years now.  Its behaviour is logical, simple to understand, and consistent with similar features of other languages (e.g. perl -e).
The proposed feature is a breaking change to one of the most widely used pieces of software in the D ecosystem. The onus is 100% on the feature proposal to provide significant justification for such a change.
Any other attitude is a fundamentally irresponsible attitude to maintaining a tool that LOTS of people rely on.
I dont know why your assuming how I'm thinking about this. I'm just asking you to provide examples to backup one of your arguments.
Also, how would this be a breaking change?
I dont know why your assuming how Im thinking about this.
I've defined my sense of "surprising" clearly: it's surprising if D code provided to --eval behaves differently from the same D code in other circumstances ... especially if that's a break to very long-standing previous behaviour.
Indeed, it's a pretty basic principle of maintaining widely used software that behavioural changes visible to the user should be carefully thought about and justified. From this point of view any such behavioural change is by definition surprising.
Asking questions about why that would be surprising strongly suggests a lack of understanding of that principle. Which is why I suggest the thinking is wrong-headed.
The focus needs to be on why the feature is good and important enough to justify the surprise.
Also, how would this be a breaking change?
Because rdmd --eval would produce different behaviour for the same input before and after this change.  We do not know, and should not assume, what aspects of the long-standing existing behaviour people are relying on.
I was just asking questions to gather data. But every time I ask a question you start making assumptions about what Im thinking then proceed to rant and repeat yourself. I'm going to disengage from this, conversing with you is a time sink with no benefit.
Folks, I'd like to ask that we put the focus on the questions I asked above: https://github.com/dlang/tools/pull/317#issuecomment-365777561
@WebDrake no worries. This is moving nowhere unfortunately for now because the logic to insert a writeln by default is too simplistic.
FWIW I doubt that - if it works perfectly - could break much code, because --eval and --loop are only used for temporary scripts and we are talking only about the cause in which a semi-colon is already missing, but yes of course it's a concern.
I also get the point that printing writeln might not be expected by the user who just accidentally forgot a semi-colon.
Anyhow as long as we can't easily rewrite the last expression (or have a plan on how to do this), there's really no need to worry that this will be added.
-> setting this to BLOCKED for now. Sorry about this, it was a nice idea, but it seems it's not that easy in practice...
@wilzbach OK, but I still think it would be good to be clear about the motivation and real use-cases if this is ever to be un-blocked.
"It's a nice idea" is a risky basis for behavioural change if it's not backed up by real, concrete user needs (which is not the same as "Well, then you could do THIS and THIS...").
There's a LOT of value in the simplicity and clarity that says, "--eval should just give you the exact same behaviour you would get from that D code in any other circumstances".
As I noted, perl -e seems to behave exactly like that, no magic added.
I'd like to suggest an alternative https://github.com/dlang/tools/pull/320 that IMO is better
just make a --print flag
just make a --print flag
That would be --eval-p and --loop-p then which we wouldn't be a nice interface (only "power-user" would remember this) and (2) CLI flags come at a premium nowadays. I sincerely doubt that you could convince anyone to add two new flags for this.
Anyhow, I'm not really sure on the best way to solve this problem here:
- the current approach has ambiguities
 - we could add a proper D lexer, but that would bloat rdmd heavily
 - the 
@idea by @timotheecour is nice, but I'm not sure whether this feature is important enough for such a special case 
I'm currently thinking about limiting this to a smaller subset, e.g. insert a "writeln(...);" if there's no semi-colon at the end and the beginning of the eval code can be reached by only seeing see a-Z_.()"!'+-=, but I'm not sure yet whether this would cover enough cases to be useful or maybe be even more confusing.
OTOH it would support this already: "myFile".readText.filter!(a => a == 'a').count
I'm currently thinking about limiting this to a smaller subset, e.g. insert a "writeln(...);" if there's no semi-colon at the end and the beginning of the eval code can be reached by only seeing see a-Z_.()"!'+-=, but I'm not sure yet whether this would cover enough cases to be useful or maybe be even more confusing.
The core problem here is that whatever solution is taken, it involves creating some magical alternative language that looks like D but behaves differently in very subtle ways.