January 15, 2013
On 01/15/13 12:21, bearophile wrote:
> Artur Skawina:
> 
>> Library territory. There's no need to put this in a D compiler.
> 
> One of the threads about possible ways to allow to implement that in library code:
> 
> http://forum.dlang.org/thread/nxhsgwliuwdgidaoudud@forum.dlang.org
> 
> 
>> Except if you'd like to have 'printf("%.2g", d)' instead of 'printf!"%.2g"(d)' syntax.
> 
> In some cases I don't mind a syntax like 'printf!"%.2g"(d)'. But I'd like D to offer ways to remove/avoid template bloat in most of those cases.

You can't both avoid template bloat *and* statically check the arguments. Statically checking dynamic data is not possible, obviously. But it's not always a problem, as as long as everything is properly inlined the overhead can be /less/ than zero. Anyway, a way to do these check right now could be something like:

   auto printf(string fmt, A...)(A a) /*@inline*/ {
      static bool isFlag(char c) {
         switch (c) {
            case '0':  case '#': case '-': case ' ': case '+':
            case '\'': case 'I': // Non-std.
               return true;
            default: return false;
         }
      }
      static bool checkArgs(B...)(string fmt) {
         if (!__ctfe)
            assert(0, "This function relies on bounds checks happening at CT");
         while (fmt.length && fmt[0]!='%')
            fmt = fmt[1..$];
         if (fmt.length==0)
            return true;
         static if (B.length==0)
            return fmt.length==0;
         else {
            size_t skip = 1;
            // Flags
            while (isFlag(fmt[skip]))
               ++skip;
            // Width
            while (fmt[skip]>='0' && fmt[skip]<='9')
               ++skip;
            // Precision
               // XXX skip \.[0-9]* , \.\*, \.[0-9]+\$
            // Length modifier
               // XXX skip them.
            // Conversion spec
            if (
                (fmt[skip]=='d' && is(B[0]==int))
             || (fmt[skip]=='g' && is(B[0]==double))
             || (fmt[skip]=='s' && is(typeof(cast()*B[0])==char))
             /* XXX etc */
                )
               return checkArgs!(B[1..$])(fmt[skip+1..$]);
            assert(0, "printf format error: '" ~ fmt ~ "', remaining args: " ~ B.stringof);
         }
      }

      static assert(checkArgs!A(fmt), "Invalid or unsupported printf args");

      import si = std.stdio, std.string;
      return si.printf(toStringz(fmt), a);
   }

   void main() {
      printf!"Pi == %d.%d != %3d\n"(3, 14, 314);
      printf!"Pi == %d.%d == %g\n"(3, 14, 3.14);
      printf!"Pi == %d.%d == %g == %s\n"(3, 14, 3.14, "3.14".ptr);

      // correctly flagged as invalid:
      //printf!"%"(42);
   }

But ideally the syntax should be

   printf(A...)(static string s, A a)

which would be "lowered" to the equivalent of

   printf(string s, A...)(A a)

and similarly:

   printf(A...)(alias a, A a)

should behave as

   print(alias a, A...)(A a)


Having this work just for templated functions would probably be ok.

artur
January 15, 2013
Artur Skawina:

> You can't both avoid template bloat *and* statically check the arguments.

In a well designed statically compiled language you don't need to instantiate templates and let them generate binary code to statically verify a condition. What's needed to test compile time arguments is just some compile-time computation; there is no need for such computation to leave any trace in the resulting binary. Beside the idea of "ghost types" (it's not a Pokemon), see also this little thread:

http://forum.dlang.org/thread/nxhsgwliuwdgidaoudud@forum.dlang.org

D needs ways to avoid some template bloat in the first place, not just to remove it later.

In some cases I'd like to write code like this, but to not let this generate different template instantiations (this means x is really a run-time value, but it's required to be known at compile-time):

void foo(int x)(string s) {}

Bye,
bearophile
January 15, 2013
On 01/15/2013 11:57 AM, mist wrote:
> Well, probably I am playing "good vision nazi" here, as 12 font size
> seems HUGE to me, far beyond the comfort zone.

It's just preference. I do not have any problems with font size 9.
January 15, 2013
On Tuesday, 15 January 2013 at 13:55:53 UTC, Timon Gehr wrote:
> On 01/15/2013 11:57 AM, mist wrote:
>> Well, probably I am playing "good vision nazi" here, as 12 font size
>> seems HUGE to me, far beyond the comfort zone.
>
> It's just preference. I do not have any problems with font size 9.

I do not know of any editor that does not support "ctrl + scroll" to change the font sizes on the fly.

I always change the font size of my editor, depending on how concentrated I am, my position in my seat, or by how complicated the current algorithm is. Or simply if somebody is looking over my shoulder.

Your editor's font size should not be statically dictated by a single number.
January 15, 2013
On Tuesday, 15 January 2013 at 11:43:20 UTC, Simen Kjaeraas wrote:
> On 2013-58-15 11:01, Russel Winder <russel@winder.org.uk> wrote:
>
>> On Mon, 2013-01-14 at 11:24 -0800, Walter Bright wrote:
>>> Quite a nice read on the coding style used in Doom.
>>>
>>> http://kotaku.com/5975610/the-exceptional-beauty-of-doom-3s-source-code?post=56177550
>>
>> On the other hand I don't like some parts of the style he is putting
>> forward as good.
>>
>> Go has an extreme position on this, there is one and only one style of
>> code that is acceptable, the one defined in the gofmt program that is
>> used to format all Go code. I happen not to like some parts of it, but I
>> live with the enforced style.
>>
>> Python is less extreme, in that there are many styles of code allowed,
>> but there is PEP-8 which is "Python style as Guido intended".  This is
>> supported by the pep8 program for enforcing elements of style. I have
>> disagreement with some of the choices, but I live with it, and format my
>> code to PEP-8 except for the line length rule – which is just so 1980s.
>>
>> C, C++, D, Fortran, Groovy, probably need to learn a lesson from one or
>> other of these.
>>
>> The issue is that having a single global style standard for a
>> programming language makes it easier to read code in that language.
>
> I agree a canonical form could be nice. Even so, I am firmly of the
> opinion that such should not be forced upon programmers. Prettifiers certainly can help here.

Not really; prettiffiers works for 99% of the code and mess the remaining 1%, that's why it is better to "force" programmers to use one style and not relying on a tool..

January 15, 2013
On 01/15/13 14:25, bearophile wrote:
> Artur Skawina:
> 
>> You can't both avoid template bloat *and* statically check the arguments.
> 
> In a well designed statically compiled language you don't need to instantiate templates and let them generate binary code to statically verify a condition. What's needed to test compile time arguments is just some compile-time computation; there is no need for such computation to leave any trace in the resulting binary.

You do realize that the code I posted in the previous message gave you static verification at compile time and _zero_ runtime overhead? It's incomplete and adds a toStringz call because it's just a POC. Actually that call can be dropped, assuming a template string parameter is always null-terminated (which could be specced that way), and then:

   void main() {
      printf!"Pi == %d.%d == %g == %s\n"(3, 14, 3.14, "3.14".ptr);
   }

compiles to:

   <_Dmain>:
       55                      push   %ebp
       89 e5                   mov    %esp,%ebp
       83 ec 28                sub    $0x28,%esp
       dd 05 88 d7 06 08       fldl   0x806d788
       c7 44 24 14 64 d7 06    movl   $0x806d764,0x14(%esp)
       08
       dd 5c 24 0c             fstpl  0xc(%esp)
       c7 44 24 08 0e 00 00    movl   $0xe,0x8(%esp)
       00
       c7 44 24 04 03 00 00    movl   $0x3,0x4(%esp)
       00
       c7 04 24 69 d7 06 08    movl   $0x806d769,(%esp)
       e8 4c f2 ff ff          call   8049100 <printf@plt>
       31 c0                   xor    %eax,%eax
       c9                      leave
       c3                      ret

You can't get any less overhead than this; not even when using a "well designed statically compiled language".

Being able to easily force evaluation at compile time and even a compile-time
mutable ephemeral storage class would be good ideas, but are not necessary for
this (they would make some things simpler, eliminate the need for recursion etc - yes).

> Beside the idea of "ghost types" (it's not a Pokemon), see also this little thread:
> 
> http://forum.dlang.org/thread/nxhsgwliuwdgidaoudud@forum.dlang.org
> 
> D needs ways to avoid some template bloat in the first place, not just to remove it later.
> 
> In some cases I'd like to write code like this, but to not let this generate different template instantiations (this means x is really a run-time value, but it's required to be known at compile-time):
> 
> void foo(int x)(string s) {}

A /run-time value known at compile-time/ is an oxymoron.

How would your above function to differ from this one
'void foo(alias x)(string s) {}' ?
Are you asking for 'void foo(alias int x)(string s) {}'?


artur
January 15, 2013
> Not really; prettiffiers works for 99% of the code and mess the
> remaining 1%, that's why it is better to "force" programmers to
> use one style and not relying on a tool..

ok but one can argue that having an coding standard defined by the community (like design and syntax of D) plus an standard (buildin) prettyprinter like goformat could be much better then the current known tools out there


January 15, 2013
Artur Skawina:

> static assert(checkArgs!A(fmt), "Invalid or unsupported printf args");

A template constraint is better, I think.


>You can't get any less overhead than this; not even when using a "well designed
statically compiled language".<

Maybe if you compile that with dmd and you look in the binary I think you will find some stuff related to that that's not needed.


>> void foo(int x)(string s) {}
>
> A /run-time value known at compile-time/ is an oxymoron.
>
> How would your above function to differ from this one
> 'void foo(alias x)(string s) {}' ?
> Are you asking for 'void foo(alias int x)(string s) {}'?

That wasn't an important request, feel free to ignore it.

What I was trying to say is not impossible. The run-time semantics of this:

void foo(static int x)(string s) {}

Is meant to be the same as:

void foo(int x, string s) {}

The only difference is that the compiler requires x to be statically known (but then you can't use specialize code on the value of x, because that's really not a template function).

This is also allowed, and it's similar to what we were discussing about:

void foo(static int x)(string s) if (predicate(x)) {}

Bye,
bearophile
January 15, 2013
On Tue, 2013-01-15 at 15:07 +0100, monarch_dodra wrote: […]
> 
> I do not know of any editor that does not support "ctrl + scroll" to change the font sizes on the fly.

Emacs, VIM,…

[…]
> Your editor's font size should not be statically dictated by a single number.

It depends on whether you want all the text to be a single size in which case yes just one number to set the font size ;-)
-- 
Russel. ============================================================================= Dr Russel Winder      t: +44 20 7585 2200   voip: sip:russel.winder@ekiga.net 41 Buckmaster Road    m: +44 7770 465 077   xmpp: russel@winder.org.uk London SW11 1EN, UK   w: www.russel.org.uk  skype: russel_winder


January 15, 2013
On Tue, Jan 15, 2013 at 11:23:40AM +0100, FG wrote:
> On 2013-01-15 09:29, monarch_dodra wrote:
> >I still prefer "writeln" over "writefln". While writefln issafe, you can still botch the amount of args, and or flag types, in which case writefln will throw. Writeln never throws (due to a code error).
> 
> What about the argument that a format string makes translation easier?

Current format string syntax still has a ways to go before it can make translation easier. Consider this example:

	writeln("%s is found in %s", file.name, dir.name);

Sounds ideal for translation, right? Except that it's not. First, reading the format string alone says nothing about what meaning is intended. What is found in a what? Also, it doesn't let you vary the word order correctly. Nor does it let you perform inflection correctly.

For true ease of translation, you need:

1) Logical naming of format arguments, e.g.:

	"%{filename} is found in %{dirname}"

and of course, some way to associate logical names with actual arguments.

2) Some way to indicate the function of each word so that inflection can be cone correctly, e.g.:

	"%{filename.nominative} is found in %{dirname.locative}"

or something like that, in languages where words change form depending on function. There will, of course, need to be requisite mechanisms for interpreting these word function identifiers.

3) Some way to indicate multiplicity:

	"1 file was found" vs. "2 files were found"

would require the quantity of files to be passed to the formatting function so that the appropriate translation can be selected. Keep in mind the different languages have different rules as to how to map quantity to word forms; just because English has only two forms (singular, plural) doesn't mean that that's enough. Russian, for example, requires 3 distinct forms: one for singular, one for numbers 2-4, a third for 5 onwards (with the second form recurring for selected subranges of the latter).

Current format strings are far from making translation truly easier.


T

-- 
Philosophy: how to make a career out of daydreaming.