Skip to content

Instantly share code, notes, and snippets.

@rikkimax
Last active April 4, 2019 18:47
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rikkimax/e9bee9fd1704aab1dcb1dafc26d3207d to your computer and use it in GitHub Desktop.
Save rikkimax/e9bee9fd1704aab1dcb1dafc26d3207d to your computer and use it in GitHub Desktop.
DIP 1020 review 1
  • Angle brackets, may be hard to find given relationship with templates Potential solutions include @named
  • External access of template parameters externally needs justification
  • Interaction with eponymous templates, invalid
  • "Future proposals" sections should probably have a full rewrite to indicate its for recognizing desirable semantics that are out of scope.
  • Not in competition with in place struct initialization, different purposes
  • More headings (break down behavior)
  • Reorder of arguments does not change at symbol site, only at the argument side
  • Overload resolution code is flawed with illegal code
  • Compare and contrast example code
  • Logging case demonstrates that for functions unnamed should be the default API wise
  • Duplicate naming is bad, flagging of a parameter as named is better
  • Partial reordering needs examples!
  • Angle bracket syntax will have problems if the parser doesn't peek one token ahead of >.
  • Partial reordering why?

Angle brackets, may be hard to find given relationship with templates

Agreed.

The angle bracket syntax was chosen in the current iteration of the DIP because it satisfies these criteria:

  1. For a type on template parameters without the curved brackets (the only reason I indulged this requirement is because of the keyword)
  2. As template parameters
  3. As function parameters
  4. Opt-in, easy to convert to and from
  5. Consistent between all the above points

Alternative designs including the usage of @named attribute is desirable, but require further research.

So far any attempt to satisfy these requirements has failed. All other characters that have both an open and a close pair on regular keyboards are already in use by D in respect to types. Overloading their usage further in the same design space would cause more harm than good.

The first point is a feature I want, which cannot be meet in using the @named attribute design. Alas, perfect is the enemy of good, which means I'm going to have to compromise and remove it for other potential designs.

After some research into dmd.parse.d, the angle bracket syntax will require peeking into the next token when finding a '>' character as part of expression parsing. If the next token is valid for an expression instead of comma or closed bracket, then expression else end of named parameter definition. This complication makes this syntax less than desirable although not a blocker. Which confirms that yes alternative designs certainly should be considered.

External access of template parameters externally needs justification

After further research, I can confirm that I cannot find any examples of named parameters being used as a first class citizens of meta-programming similar to what D has. This means that any work towards named template parameters must evolve from what we have already got.

Template parameters whose name has not been specified as part of their argument list demonstrate that their purpose is internal to the type and results in minimal concern to the initializer. Not all cases will appear this way. For example a type specified as the first argument on a data structure would imply that it is the type of the data being stored. But a boolean following it to enable GC interactions does not explain what it is there for hence why std.typecons.Flag exists.

For best effect a named template parameter is a subset of template parameters that the initializer has specifically set beyond the standard unnamed set. Because the initializer specifically requested it (or could in the future), it must therefore care about its value even if it has not been set. Being able to access this value without the usage of the is expression to extract it, demonstrates that it is part of the behavior that the type exhibits.

The above conclusions are the basis for my decision to expose a named template parameter as a member.

Interaction with eponymous templates, invalid

The current logic is that if a template parameter name matches the template's, it will not act as a eponymous template. This should extend to named template parameters as well.

The spec makes it clear that template parameters cannot make an eponymous template.

"If a template contains members whose name is the same as the template identifier": yes, a named template parameter is visible as a member, but it should not be a member in the AST "and if the type or the parameters type of these members include at least all the template parameters then these members are assumed to be referred to in a template instantiation:": potentially no

The semantics are uncharged by the DIP. I.e. named template parameters should not appear in a __traits(allMembers, T) request.

Not in competition with in place struct initialization, different purposes

The facilitation of passing of arguments to a given function/template is done by either a named or unnamed parameter. In place struct initialization provides domain objects a way to be easily constructed and passed via one of the parameters. Individually an in place struct initialization syntax would be capable of emulating named arguments if you are willing to access and define a struct which is the parameter list.

Consider:

void myFunction(Rect, <bool myFlag=false>) {}
myFunction({x: 1, y: 1, width: 9, height: 9}, myFlag: true);

In the function call the position and size is grouped as a domain object keeping the values together. Without in place struct initialization they will be separate in the arguments list and could potentially be not together with full reordering enabled. Which is poor programming. The flag could be an unnamed argument as well. But then you couldn't put it at the start or move it around in the arguments list as appropriate. If the flag, size and position arguments are stored in a struct, without using multiple layers of in place struct initialization you would not be keeping the domain objects together.

These two language features do not subtract from each other. They can be used to complement, with a well designed API.

Reorder of arguments does not change at symbol site, only at the argument side

When a function with named parameters is compiled, its parameter order is fixed. The ordering in the argument list will be altered to match the parameters of the function. It does not matter what order the caller chose as long as it is valid.

The exact order of the arguments being passed to a function has not been defined as of yet. But because this is an extern(D) only feature, what is chosen should not be of concern to non-compiler developers and can be changed freely without error. The same can be said about template named+unnamed parameter order.

Partial reordering why?

There are three philosophies of thought about ordering of named arguments that I have found so far.

  1. Full
  2. None
  3. Some form of partial

Full and none have very vocal groups in the D programming language community. Each philosophy has its advantages and disadvantages. With many a bad code written and abused of this feature in either camp. The 'default' option this DIP will offer is a partial reordering that does not restrict to the placement of the start of the named arguments or where the unnamed arguments end. The strong requirement of order between the named arguments that must match relatively to the parameters that they match to, exists to prevent full reordering. It is a sane default but does have the weakness that the order the parameters are defined it may not be suitable for the user.

If at some point the option desired changes, the change could be very breaking or it could be minimal in damages:

  • To convert partial to full would require removing of code in a frontend. No breakage.
  • To convert partial to none would require adding of code in the frontend. Breakage but it could be a deprecation warning followed by an error.
  • To convert full to none would require adding of code in the frontend with significant breakage.
  • To convert none to full would require removing of code in the frontend with no breakage.

For functions full is a clear winner for argument reordering, giving minimal restrictions and maximum use cases. But for template parameters it is not so clear cut. As per "External access of template parameters externally needs justification" we do not have the evidence to support what behavior is desirable at this point in time. Being conservative at the current time seems to be best way forward until we have experience with this potential language feature.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment