Jump to page: 1 2
Thread overview
Postfix type notation - readability and parsing?
Mar 05
aliak
Mar 07
aliak
Mar 06
Basile B.
Mar 07
Basile B.
Mar 07
aliak
Mar 08
Dennis
Mar 07
Kagamin
March 05
This is the most "readable" formatting I could think of for long declarations with current syntax.

static immutable Option!(ushort, "p|port", "Sets the port used for serving.", "PORT", 8888)
        port;
static immutable Option!(int, "db-port", "Sets the port to use for connecting to the db", "DB_PORT", 5432)
        dbPort;
static immutable Option!(string, "db-host", "Sets the port to use for connecting to the db", "DB_HOST", "127.0.0.1")
        dbHost;

The template declaration is quite long so:

1) putting the variable name at the end makes it hard to see and you'd need to scroll horizontally to get to see what this type is for.

2) doing it like the above is confusing to see which name belongs to which type because you're so used to a type declaration being on one line.

3) Splitting it over multiple lines like:

static immutable Option!(
    ushort,
    "p|port",
    "Sets the port used for serving.",
    "PORT",
    8888
) port;

Turns a potentially X line file in to a X * 10 line file, and you have scroll just to see what all the variables are

4) Deciding to go with a mixin approach so you can have the variable name on the left and on the same line like:

mixin Option!("port", ushort, "p|port",  "Sets the port used for serving.", "PORT",  8888);

destroys any chance of auto completion on the enclosing type, and also means you have to implement two types (the mixin template and the underlying type - i.e. Option and OptionImpl)

5) putting it on the right after an opAssign ala:

auto port = Option!(...)

means you can't initialize any immutable data in constructors since the initialization happens in the declaration line.

If we had postfix then:

static immutable port: Option!(ushort, "p|port", ...);
static immutable dbPort: Option!(int, "db-port",...)
static immutable dbHost: Option!(string, "db-host",...)

Without line wrapping you can see all the main information you need with a glance of the code. Isn't that more readable (in this scenario)?

The same would apply for functions with long types like this:

SomeType!("this is the first", int, "some other thing goes here" foo() {
}

vs

function foo(): SomeType!("this is the first", int, "some other thing goes here") {
}

You can't find out that it's a function until you move your eyes all the way to the right in the former, but the latter is instantaneously apparent.

Consistency could also increase because you will have this:

auto a: int;
const b = 3;

instead of:

int a;
const b = 3;

The type is an inferred type or an explicit type but they can bother be on the right?

And finally, I'm curious how this would effect parsing? Maybe someone familiar with dmd internals can say if things would be easier? Because it feels like currently you need to look ahead when you see "int identifier" - is it a variable or function? Can't know until you go farther right? Are there other situations like this?

Cheers,
- Ali
March 06
On Tuesday, 5 March 2019 at 22:29:33 UTC, aliak wrote:
> 3) Splitting it over multiple lines like:
>
> static immutable Option!(
>     ushort,
>     "p|port",
>     "Sets the port used for serving.",
>     "PORT",
>     8888
> ) port;
>
> Turns a potentially X line file in to a X * 10 line file, and you have scroll just to see what all the variables are

I actually think this version looks the best out of all the examples you've given. In fact, I'd probably split the declaration over multiple lines even if the type were placed on the right.
March 06
On Tuesday, 5 March 2019 at 22:29:33 UTC, aliak wrote:
> 1) putting the variable name at the end makes it hard to see and you'd need to scroll horizontally to get to see what this type is for.
>
> 2) doing it like the above is confusing to see which name belongs to which type because you're so used to a type declaration being on one line.
>
> 3) Splitting it over multiple lines like:
>
> static immutable Option!(
>     ushort,
>     "p|port",
>     "Sets the port used for serving.",
>     "PORT",
>     8888
> ) port;
>
> 4) Deciding to go with a mixin approach so you can have the variable name on the left and on the same line like:
>
> mixin Option!("port", ushort, "p|port",  "Sets the port used for serving.", "PORT",  8888);
>
> 5) putting it on the right after an opAssign ala:
>
> auto port = Option!(...)


Just to add a 6) to the mix:

alias port = Option!(immutable ushort, "p|port", "Sets the port used for serving.", "PORT", 8888);

static this() {
    port = 1234;
}

template Option(T, string s, string s2, string s3, T defaultValue) {
    import std.traits : Unqual, CopyTypeQualifiers;
    struct Impl {
        Unqual!T _value;
        alias _value this;
        this(T t) {}
    }
    CopyTypeQualifiers!(T, Impl) Option;
}

// Also does the right thing in structs and classes:

struct S {
    static alias port = Option!(immutable ushort, "p|port", "Sets the port used for serving.", "PORT", 8888);
}

static this() {
    S.port = 1234;
}

--
  Simen
March 06
On Wednesday, 6 March 2019 at 07:53:42 UTC, Simen Kjærås wrote:
> alias port = Option!(immutable ushort, "p|port", "Sets the port used for serving.", "PORT", 8888);

Of course, one issue is the lack of __GENSYM__, meaning that this will only declare one variable, with two aliases:

alias a = Option!(int, "", "", "", 0);
alias b = Option!(int, "", "", "", 0);

unittest {
    assert(&a == &b);
}

--
  Simen
March 06
On Wednesday, 6 March 2019 at 07:53:42 UTC, Simen Kjærås wrote:
> Just to add a 6) to the mix:
>
> alias port = Option!(immutable ushort, "p|port", "Sets the port used for serving.", "PORT", 8888);
>
> static this() {
>     port = 1234;
> }

Option!(...) is a type, not a value, so this should actually be written as:

alias PortOption = Option!(...);
PortOption port;

static this() {
    port = 1234;
}
March 06
On Wednesday, 6 March 2019 at 17:27:55 UTC, Paul Backus wrote:
> On Wednesday, 6 March 2019 at 07:53:42 UTC, Simen Kjærås wrote:
>> Just to add a 6) to the mix:
>>
>> alias port = Option!(immutable ushort, "p|port", "Sets the port used for serving.", "PORT", 8888);
>>
>> static this() {
>>     port = 1234;
>> }
>
> Option!(...) is a type, not a value, so this should actually be written as:
>
> alias PortOption = Option!(...);
> PortOption port;
>
> static this() {
>     port = 1234;
> }

Not if you use the code in my post, which included a definition of Option to support exactly the code I wrote.

--
  Simen
March 06
On Tuesday, 5 March 2019 at 22:29:33 UTC, aliak wrote:
> This is the most "readable" formatting I could think of for long declarations with current syntax.
>
> static immutable Option!(ushort, "p|port", "Sets the port used for serving.", "PORT", 8888)
>         port;
> static immutable Option!(int, "db-port", "Sets the port to use for connecting to the db", "DB_PORT", 5432)
>         dbPort;
> static immutable Option!(string, "db-host", "Sets the port to use for connecting to the db", "DB_HOST", "127.0.0.1")
>         dbHost;
>
> The template declaration is quite long so:
>
> 1) putting the variable name at the end makes it hard to see and you'd need to scroll horizontally to get to see what this type is for.
>
> 2) doing it like the above is confusing to see which name belongs to which type because you're so used to a type declaration being on one line.
>
> 3) Splitting it over multiple lines like:
>
> static immutable Option!(
>     ushort,
>     "p|port",
>     "Sets the port used for serving.",
>     "PORT",
>     8888
> ) port;
>
> Turns a potentially X line file in to a X * 10 line file, and you have scroll just to see what all the variables are
>
> 4) Deciding to go with a mixin approach so you can have the variable name on the left and on the same line like:
>
> mixin Option!("port", ushort, "p|port",  "Sets the port used for serving.", "PORT",  8888);
>
> destroys any chance of auto completion on the enclosing type, and also means you have to implement two types (the mixin template and the underlying type - i.e. Option and OptionImpl)
>
> 5) putting it on the right after an opAssign ala:
>
> auto port = Option!(...)
>
> means you can't initialize any immutable data in constructors since the initialization happens in the declaration line.
>
> If we had postfix then:
>
> static immutable port: Option!(ushort, "p|port", ...);
> static immutable dbPort: Option!(int, "db-port",...)
> static immutable dbHost: Option!(string, "db-host",...)
>
> Without line wrapping you can see all the main information you need with a glance of the code. Isn't that more readable (in this scenario)?
>
> The same would apply for functions with long types like this:
>
> SomeType!("this is the first", int, "some other thing goes here" foo() {
> }
>
> vs
>
> function foo(): SomeType!("this is the first", int, "some other thing goes here") {
> }
>
> You can't find out that it's a function until you move your eyes all the way to the right in the former, but the latter is instantaneously apparent.
>
> Consistency could also increase because you will have this:
>
> auto a: int;
> const b = 3;
>
> instead of:
>
> int a;
> const b = 3;
>
> The type is an inferred type or an explicit type but they can bother be on the right?
>
> And finally, I'm curious how this would effect parsing? Maybe someone familiar with dmd internals can say if things would be easier? Because it feels like currently you need to look ahead when you see "int identifier" - is it a variable or function? Can't know until you go farther right? Are there other situations like this?
>
> Cheers,
> - Ali

  The "Postfix type notation", to quote your naming of it, can be ambiguous and it breaks the C-ish looking style of D. Example of ambiguity:

  function foo(): function():int [] {}

What is the return type of foo ?

1. an array of `function():int` ?
2. a function pointer returning an array of int ?

I think it's a bad and unrealistic idea for D. Having two different styles for this would be a major inconsistency. That being said you could certainly hack the compiler to get this style working. It's only a grammatical change and the same AST could be reused.


  Now to come back to the problem you concretely encounter, I know what your are trying to do and you can do it otherwise: use an UDA. Instead of

    static immutable Option!(ushort, "p|port", "Sets the port used for serving.", "PORT", 8888) port;


try to do

    @Option!("p|port", "Sets the port used for serving.", "PORT", 8888)
    static immutable ushort port;

you see ?
March 07
On Tuesday, 5 March 2019 at 22:29:33 UTC, aliak wrote:
> This is the most "readable" formatting I could think of for long declarations with current syntax.
>
> static immutable Option!(ushort, "p|port", "Sets the port used for serving.", "PORT", 8888)
>         port;
> static immutable Option!(int, "db-port", "Sets the port to use for connecting to the db", "DB_PORT", 5432)
>         dbPort;
> static immutable Option!(string, "db-host", "Sets the port to use for connecting to the db", "DB_HOST", "127.0.0.1")
>         dbHost;
>
> The template declaration is quite long so:

This works:

struct Option(T...)
{
    string a;
}

static port = immutable Option!(ushort, "p|port", "Sets the port used for serving.", "PORT", 8888)();
March 07
On Wednesday, 6 March 2019 at 18:06:34 UTC, Basile B. wrote:
> On Tuesday, 5 March 2019 at 22:29:33 UTC, aliak wrote:
>   Now to come back to the problem you concretely encounter, I know what your are trying to do and you can do it otherwise: use an UDA. Instead of
>
>     static immutable Option!(ushort, "p|port", "Sets the port used for serving.", "PORT", 8888) port;
>
>
> try to do
>
>     @Option!("p|port", "Sets the port used for serving.", "PORT", 8888)
>     static immutable ushort port;
>
> you see ?

Well since it's an uda you change the thing to a non template struct:

  @Option("p|port", "Sets the port used for serving.", "PORT", 8888)
  static immutable ushort port;

By the way i proposed this because I did something like that which worked quite correctly although no finished: https://github.com/Basile-z/iz/blob/d9e36efced7069600b2d04b5a30fe905d6125347/import/iz/options.d#L602


March 07
On Wednesday, 6 March 2019 at 08:09:48 UTC, Simen Kjærås wrote:
> On Wednesday, 6 March 2019 at 07:53:42 UTC, Simen Kjærås wrote:
>> alias port = Option!(immutable ushort, "p|port", "Sets the port used for serving.", "PORT", 8888);
>
> Of course, one issue is the lack of __GENSYM__, meaning that this will only declare one variable, with two aliases:
>
> alias a = Option!(int, "", "", "", 0);
> alias b = Option!(int, "", "", "", 0);
>
> unittest {
>     assert(&a == &b);
> }
>
> --
>   Simen

Thanks for that code above!

And hmm.. __GENSYM__ ... is this documented anywhere? (I found a post by you on the forum about it but nothing in the docs)
« First   ‹ Prev
1 2