November 02, 2014
Walter Bright:

> I don't see the use cases, in mine or other code.
> Designing a language feature around printf is a mistake.

I agree. Let's talk about other use cases.


> I've considered the feature, and looked at code. It just doesn't happen very often.

I have written plenty of D code (perhaos 240 thousand lines so far) and I've seen several cases where the ideas I've suggested can be useful.

If you define a rangedInt struct:

void main() {
    alias I10 = rangedInt!(int, 0, 10);
    I10[] arr = [1, 5, 12, 3];
}


My ideas should be able to spot the bug in that array literal at compile-time. Ada2012 is able to do the same. Currently D can't do that.

The same is possible with other values, including complex ones as kinds of game data. If I define a finite state machine the enum precondition is able to spot malformed machines at compile time. I am able to give you more usage examples on request.

It happens often enough to justify a similar feature in Ada2012. (This is the main point of this whole discussion. The other parts of this answer are less important).



> All features have a cost/benefit to them. The costs are never zero. Laying on more and more features of minor benefit will destroy the language, and even you won't use it.

I agree. But freezing D design is not a good idea. (Note: so far I don't care for C++ interoperativity much. And I think the a good way to face GC-derived problems is to introduce memory ownership tracking in the type system).


> Oh come on. writefln is typesafe and will not crash.

It shows bugs at runtime, where they can be avoided (turning them to compile time ones) at essentially no cost for the programmer. For me this is a broken/unacceptable design (and I'm saying this since years. Glad to see Rust people agree. I think this is an example of this phenomenon: http://en.wikipedia.org/wiki/Punctuated_equilibrium  in the programming language design world).


> You could also write:
> 
>    formattedwrite!"the format string %s %d"(args ...)
> 
> if you like. The fact that nobody has bothered to suggests that it doesn't add much value over writefln().

Plenty of people have bothered, there's an implementation.


> It does some flow analysis based on previous bounds checks.

I didn't know this. I'll need to do some experiments :-)


>> On the other hand we could argue that bit flags are a sufficiently different
>> purpose to justify an annotation (as in C#) or a Phobos struct (like for the
>> bitfields) that uses mixin that implements them (there is a pull request for
>> Phobos, but I don't know how much good it is).
>
> More annotations => more annoyance for programmers. Jonathan Blow characterizes this as "friction" and he's got a very good point. Programmers have a limited tolerance for friction, and D must be very careful not to step over the line into being a "bondage and discipline" language that nobody uses.

The annotation is used only once at the definition point of the flags. So the "annotation" here is essentially a way to tell the compiler that you don't want a regular enumeration, but a flags. It's like having two different language constructs, enums and flags. So it's a way to offer the programmer a chance to express intent and make the code more expressive/readable. And this allows to make the semantics of enums more strict. It's a win-win-win situation. The real downside is increased language complexity, but as I explained in past, well designed clean features are not the main source of complexity. And formalizing a programmer idiom is often not a bad idea.


> I don't buy the notion that more complex is better. Simple and effective is the sweet spot.

I am not asking for ML-style modules in D. But ML modules aren't complex for free, they introduce important qualities in ML language and its "generics".


> It is not suboptimal.
> D is at a reasonable optimum point for this.

In my opinion it has some faults. I am not alone with this opinion. So I think it's not at the optimum.


> There are lot of tradeoffs with this, and it has been discussed extensively.

I agree, but the situation is not improving much so far. I see mostly stasis on this.


> The implication that this is thoughtlessly thrown together against all reason is just not correct.

I didn't say D implicit casts are randomly designed :-) I said that they are currently not very good or the best possible.


>> I think the size casting that loses bits is still regarded as safe.
> It is memory safe.

Probably that's why there are two kind of casts in Haskell.

Bye,
bearophile
November 02, 2014
On Saturday, 1 November 2014 at 11:31:32 UTC, bearophile wrote:
> Third part of the "A Programming Language for Games", by Jonathan Blow:
> https://www.youtube.com/watch?v=UTqZNujQOlA
>
> Discussions:
> http://www.reddit.com/r/programming/comments/2kxi89/jonathan_blow_a_programming_language_for_games/
>

Impressive work, worth watching. It finds it particularly telling that string mixins + CTFE seem to have been implemented before arrays or templates.
(There is even if(__ctfe) around 1:31:00)

It will be nice to see his take on objects, arrays, constness, and how he does templates.
November 02, 2014
On 11/1/14, 8:31 AM, bearophile wrote:
> Third part of the "A Programming Language for Games", by Jonathan Blow:
> https://www.youtube.com/watch?v=UTqZNujQOlA
>
> Discussions:
> http://www.reddit.com/r/programming/comments/2kxi89/jonathan_blow_a_programming_language_for_games/
>
>
> His language seems to disallow comparisons of different types:
>
> void main() {
>      int x = 10;
>      assert(x == 10.0); // Refused.
> }
>
>
> I like the part about compile-time tests for printf:
> http://youtu.be/UTqZNujQOlA?t=38m6s
>
> The same strategy is used to validate game data statically:
> http://youtu.be/UTqZNujQOlA?t=55m12s
>
> A screenshot for the printf case:
> http://oi57.tinypic.com/2m5b680.jpg

That is called a linter. A general linter works on an abstract syntax tree with possibly type annotations. His "linter" only works on functions. I guess he will extend it later, but he's not inventing anything new.

My opinion is that he knows C++ a lot and he's tired of some of its stuff so he's inventing a language around those. I don't think that's a good way to design a language.

D can run (some) stuff at compile time. Crystal can run (any) stuff at compile time. Rust too. Many modern languages already understood that it is very important to run things at compile time, be it to generate code or to check things.

I can understand his excitement because I got excited too when I was able to run stuff at compile time :-)

About the bytecode he generates: as someone said in the reddit discussion, having to maintain two separate language implementations (compiled and interpreted) can lead to small and subtle bugs. And, running code via an intepreter is slower than compiled code, even if the interpreter is really good. So I don't think the bytecode stuff is a really good idea.

Also, why have a dynamic array as a built-in? You can implement it yourself with pointers...
November 02, 2014
On 11/2/2014 5:44 AM, bearophile wrote:
> It happens often enough to justify a similar feature in Ada2012. (This is the
> main point of this whole discussion. The other parts of this answer are less
> important).

Why aren't you using Ada if this is critical to you? (I'm not being sarcastic, this is a fair question.)


>> All features have a cost/benefit to them. The costs are never zero. Laying on
>> more and more features of minor benefit will destroy the language, and even
>> you won't use it.
>
> I agree. But freezing D design is not a good idea.

I'm not saying "freeze the design". I'm saying that if things are wrapped in enough bubble wrap, few programmers will want to use the language. After all, I don't wear a firesuit or helmet when I drive my car.


> (Note: so far I don't care
> for C++ interoperativity much.

I understand. But poor C++ interop is preventing quite a few people from using D. Validating printf format strings is not.


>> You could also write:
>>
>>    formattedwrite!"the format string %s %d"(args ...)
>>
>> if you like. The fact that nobody has bothered to suggests that it doesn't add
>> much value over writefln().
>
> Plenty of people have bothered, there's an implementation.

1. I've heard proposals, but no implementation.
2. If it exists, why aren't you using it?
3. It is obviously doable in D. No language extension required. You can even write one and contribute it!


>> More annotations => more annoyance for programmers. Jonathan Blow
>> characterizes this as "friction" and he's got a very good point. Programmers
>> have a limited tolerance for friction, and D must be very careful not to step
>> over the line into being a "bondage and discipline" language that nobody uses.
>
> The annotation is used only once at the definition point of the flags. So the
> "annotation" here is essentially a way to tell the compiler that you don't want
> a regular enumeration, but a flags. It's like having two different language
> constructs, enums and flags.

I understand that - yet another basic type in the system. I believe you majorly underestimate the costs of these things, or even assign zero cost to them.


> So it's a way to offer the programmer a chance to
> express intent and make the code more expressive/readable. And this allows to
> make the semantics of enums more strict. It's a win-win-win situation.

Again, you badly underestimate the costs or just pretend they aren't there.


> The real
> downside is increased language complexity, but as I explained in past, well
> designed clean features are not the main source of complexity.

I must ask, have you ever designed a house? Everything is a tradeoff. Want a bigger closet? What becomes smaller as a result? Do you want a view from the kitchen window or do you want a convenient door from the kitchen to the garage? If you give the view to the kitchen, are you willing to give up the view from the study? Do you accept this change will add $10,000 to the budget? This other change will require approval from the zoning people, causing delays. How will the position of the windows make the house look from the street? And on and on.

Language design is the same thing. You can't just "explain" that the solution is to make "clean" features. Like a house design, every feature in a language interacts with every other feature.


> And formalizing a programmer idiom is often not a bad idea.

Sorry, this is just hand-waving.


>> It is not suboptimal.
>> D is at a reasonable optimum point for this.
> In my opinion it has some faults. I am not alone with this opinion. So I think
> it's not at the optimum.

A reasonable optimum point is not equal to "nobody can find any fault with it". A reasonable optimum point is where the faults are more acceptable than the known alternatives.


>> The implication that this is thoughtlessly thrown together against all reason
>> is just not correct.
>
> I didn't say D implicit casts are randomly designed :-) I said that they are
> currently not very good

I strongly reject that notion.


> or the best possible.

It's the best anyone has come up with for now.


>>> I think the size casting that loses bits is still regarded as safe.
>> It is memory safe.
> Probably that's why there are two kind of casts in Haskell.

    x & 0xFF

loses bits as well. What do you propose to do about that flaw?
November 02, 2014
Walter Bright:

> Why aren't you using Ada if this is critical to you? (I'm not being sarcastic, this is a fair question.)

It's not critical...
Ada is not fun, too much new stuff to learn and to adapt to, and I can't influence Ada evolution in any way. My hope for preferred future system language is not in Ada. Still, Ada contain some nice ideas.


> I'm not saying "freeze the design".

But we are currently close to this... Lately the only ideas I've seen seriously discussed are the ones about reference counting by Andrei. Even the proposal about the tracking of memory ownership was not much discussed.


> I'm saying that if things are wrapped in enough bubble wrap, few programmers will want to use the language. After all, I don't wear a firesuit or helmet when I drive my car.

The new pre-condition is optional (you use it for Phobos structs, etc), and for the programmer that later uses the function/struct/class its usage its totally transparent, so the wearing of firesuit/helmet metaphor is not good enough.

If I define a library type named Nibble that is represented with an ubyte and accepts only values in [0, 15] with an enum precondition, I can use it like (once Kenji patch to convert arrays of structs is merged):

Nibble[] arr = [5, 18, 3, 1];

The usage is totally transparent for the user, no firesuits or helmets are necessary or visible (yet that code will give a compile-time error).


> I understand. But poor C++ interop is preventing quite a few people from using D.

I understand and I encourage this part of D design to keep going on.


> Validating printf format strings is not.

I don't care much of printf/writef. That was just an example, and not even the most important.


> 2. If it exists, why aren't you using it?

If a writeln template with compile-time format string testing goes in Phobos I'll surely use it (despite the template bloat it will cause).


> I understand that - yet another basic type in the system.

Perhaps a good enough FlagsEnum can be implemented with pure D library code.


>> And formalizing a programmer idiom is often not a bad idea.
>
> Sorry, this is just hand-waving.

I have seen it's often true ::-) New languages are essentially invented for this purpose: to turn programmer idioms into compiler-enforced features with a short nice syntax. The idiom of passing a pointer + length to a C function is replaced by a much better dynamic array of D. Even OOP is an idiom that used to be implemented badly in C by lot of people. This list of examples can become very long.


> A reasonable optimum point is not equal to "nobody can find any fault with it". A reasonable optimum point is where the faults are more acceptable than the known alternatives.

I think the free mixing of signed and unsigned integral values is not a good idea in D. I think that there are various ways to refine immutable value range propagation.

Bye,
bearophile
November 02, 2014
On 11/2/2014 12:12 PM, bearophile wrote:
> I think the free mixing of signed and unsigned integral values is not a good
> idea in D.

It's simply not workable to put a wall between them. Every proposal for it has entailed various unfortunate, ugly, and arbitrary consequences.

Languages like Java have "solved" the problem by simply not having any unsigned types. That isn't going to work for a systems programming language.

November 02, 2014
On Sunday, 2 November 2014 at 20:12:17 UTC, bearophile wrote:
> Perhaps a good enough FlagsEnum can be implemented with pure D library code.

https://github.com/D-Programming-Language/phobos/pull/2058
November 02, 2014
On 11/1/14 6:25 PM, bearophile wrote:
> Walter Bright:
>
>> D has writefln which does not have printf's issues. There's no reason
>> to add a feature for printf.
>
> The feature we are talking about is not just for D writeln, as I've
> tried to explain several times.

Well maybe then it's time to reassess whether the point was valid and interesting.

> And D writeln is not verified at compile-time, this is silly for a
> language that tries to be reliable.

Wasn't there a pull request that allowed `writef!"%s %s"(1, 2)` in addition to what we have now? Should be easy to integrate.

> (Rust printing function is actually
> a macro and it verifies the formatting string at compile-time when
> possible. That's the only good enough option for me for a modern
> statically compiled language).

Is that a best-effort kind of approach? If so, that would be pretty bad...



Andrei

November 02, 2014
On 11/1/14 6:48 PM, H. S. Teoh via Digitalmars-d wrote:
> While writefln can be improved (Andrei has preapproved my enhancement
> request to support compile-time format string, for example), there's no
> way to make such improvements to GCC's format checking short of
> modifying the compiler itself.

Oh so it was you :o). Great idea, time to follow with implementation! -- Andrei
November 02, 2014
On 11/2/14 2:11 AM, Paolo Invernizzi wrote:
> On Sunday, 2 November 2014 at 01:28:15 UTC, H. S. Teoh via Digitalmars-d
> wrote:
>>
>> 1) Compile-time verification of format arguments -- passing the wrong
>> number of arguments or arguments of mismatching type will force
>> compilation failure. Currently, it will compile successfully but fail at
>> runtime.
>
> +1000! That would be awesome!
>
> It would be a _great_ boost in productivity during the debugging phase,
> or when we are under pressure and can't do a great job in code coverage.

Compile-time checking of format strings is nice to have, but I hardly see it as a major productivity boost. Maybe the better effect would be it serving as an example for other libraries to follow. -- Andrei