https://wiki.dlang.org/api.php?action=feedcontributions&user=Bearophile&feedformat=atom
D Wiki - User contributions [en]
2024-03-29T05:35:44Z
User contributions
MediaWiki 1.31.2
https://wiki.dlang.org/?title=Talk:DIP69&diff=5586
Talk:DIP69
2015-02-16T17:33:22Z
<p>Bearophile: Removed example because it's probably Issue 9685</p>
<hr />
<div></div>
Bearophile
https://wiki.dlang.org/?title=Talk:DIP69&diff=5585
Talk:DIP69
2015-02-15T18:52:41Z
<p>Bearophile: One example bug</p>
<hr />
<div>See one bug that DIP69 (or similar proposals) must help remove from D code:<br />
http://forum.dlang.org/post/zpuriaktffctmnljuprq@forum.dlang.org<br />
<br />
import std.range, std.algorithm, std.stdio;<br />
<br />
void foo(float[] data, float[] xs, float[] ys)<br />
{<br />
auto indices = iota(0, data.length, ys.length)<br />
.map!(xBase =><br />
iota(xBase, xBase + ys.length - 1)<br />
.map!(y =><br />
only(y, y+ys.length, y+ys.length+1, y+1))<br />
.joiner())<br />
.joiner();<br />
writeln(indices);<br />
}<br />
<br />
void main()<br />
{<br />
foo([1,2,3,4,5,6,7,8],<br />
[0.1,0.2], [10,20,30,40]);<br />
}</div>
Bearophile
https://wiki.dlang.org/?title=Talk:DIP32&diff=5323
Talk:DIP32
2015-01-08T17:43:54Z
<p>Bearophile: Added two comments</p>
<hr />
<div>== About $identifier ==<br />
<br />
Why not require normal declaration syntax, when a variable should be declared in unpacking?<br />
<br />
Suggested in DIP:<br />
<source lang="D"><br />
switch (tup) {<br />
case {1, 2}:<br />
case {$, 2}:<br />
case {1, x}:<br />
default:<br />
}<br />
// -----------------------------<br />
int x = 1;<br />
if (auto {$x, y} = coord) { ... }<br />
</source><br />
<br />
My suggestion:<br />
<source lang="D"><br />
switch (tup) {<br />
case {1, 2}:<br />
case {$, 2}:<br />
case {1, auto x}:<br />
default:<br />
}<br />
// -----------------------------<br />
int x = 1;<br />
if ({x, auto y} = coord) { ... }<br />
</source><br />
<br />
This would be more consistent with how '''if''' usually works (expression syntax => use existing variable, declaration syntax => declare variable initialized with the value of the comparison), doesn't require this special syntax which is used nowhere else in the language, and makes it obvious that a declaration takes place.<br />
<br />
It also allows to use unpacking everywhere:<br />
<br />
<source lang="D"><br />
int x;<br />
{x, int y} = tup;<br />
</source><br />
<br />
== Variable declaration in case statements ==<br />
<br />
Care must be taken when variable declaration is used in combination with fall through / '''goto case''' in case statements:<br />
<br />
<source lang="D"><br />
switch (tup) {<br />
case {1, 2}:<br />
case {$, 2}:<br />
goto case;<br />
case {1, x}:<br />
// what is x if tup == {1, 2}?<br />
}<br />
</source><br />
<br />
==Tuple Slicing?==<br />
<br />
If you want you can also add a slicing syntax for tuples:<br />
<br />
<source lang="D">auto t1 = {10, 20.5, "foo"};<br />
auto t2 = t1[1 .. $];</source><br />
<br />
==Return ref value in tuple?==<br />
This is currently not possible with Phobos tuples:<br />
<br />
<source lang="D">{ref int, int} foo(ref int x) {<br />
return tuple(x, 5);<br />
}<br />
void main() {}</source><br />
<br />
==Built-in tuples should avoid Phobos Tuple const problems==<br />
<br />
Like this one:<br />
<br />
<source lang="D">void main() {<br />
import std.typecons: Tuple;<br />
Tuple!int t1;<br />
alias T = const Tuple!int;<br />
T t2;<br />
t1 = t2; // OK<br />
t1 = T(); // Error<br />
}</source></div>
Bearophile
https://wiki.dlang.org/?title=Talk:DIP32&diff=5311
Talk:DIP32
2015-01-05T12:30:16Z
<p>Bearophile: Tuple Slicing?</p>
<hr />
<div>== About $identifier ==<br />
<br />
Why not require normal declaration syntax, when a variable should be declared in unpacking?<br />
<br />
Suggested in DIP:<br />
<source lang="D"><br />
switch (tup) {<br />
case {1, 2}:<br />
case {$, 2}:<br />
case {1, x}:<br />
default:<br />
}<br />
// -----------------------------<br />
int x = 1;<br />
if (auto {$x, y} = coord) { ... }<br />
</source><br />
<br />
My suggestion:<br />
<source lang="D"><br />
switch (tup) {<br />
case {1, 2}:<br />
case {$, 2}:<br />
case {1, auto x}:<br />
default:<br />
}<br />
// -----------------------------<br />
int x = 1;<br />
if ({x, auto y} = coord) { ... }<br />
</source><br />
<br />
This would be more consistent with how '''if''' usually works (expression syntax => use existing variable, declaration syntax => declare variable initialized with the value of the comparison), doesn't require this special syntax which is used nowhere else in the language, and makes it obvious that a declaration takes place.<br />
<br />
It also allows to use unpacking everywhere:<br />
<br />
<source lang="D"><br />
int x;<br />
{x, int y} = tup;<br />
</source><br />
<br />
== Variable declaration in case statements ==<br />
<br />
Care must be taken when variable declaration is used in combination with fall through / '''goto case''' in case statements:<br />
<br />
<source lang="D"><br />
switch (tup) {<br />
case {1, 2}:<br />
case {$, 2}:<br />
goto case;<br />
case {1, x}:<br />
// what is x if tup == {1, 2}?<br />
}<br />
</source><br />
<br />
==Tuple Slicing?==<br />
<br />
If you want you can also add a slicing syntax for tuples:<br />
<br />
<source lang="D">auto t1 = {10, 20.5, "foo"};<br />
auto t2 = t1[1 .. $];</source></div>
Bearophile
https://wiki.dlang.org/?title=DIP60&diff=4061
DIP60
2014-04-21T09:38:57Z
<p>Bearophile: More behaviours in presence of optimizations</p>
<hr />
<div>{| class="wikitable"<br />
!Title:<br />
!'''DIP Add @nogc Function Attribute'''<br />
|-<br />
|DIP:<br />
|60<br />
|-<br />
|Version:<br />
|1.2<br />
|-<br />
|Status:<br />
|Draft<br />
|-<br />
|Created:<br />
|2014-4-15<br />
|-<br />
|Last Modified:<br />
|2014-4-18<br />
|-<br />
|Author:<br />
|Walter Bright<br />
|-<br />
|Links:<br />
|[[DIP60/Archive]] — [https://github.com/D-Programming-Language/dmd/pull/3455 pull request] — [http://forum.dlang.org/post/lijoli$2jma$1@digitalmars.com forum discussion]<br />
|}<br />
<br />
== Abstract ==<br />
The @nogc function attribute will mark a function as not making any allocations using the GC.<br />
<br />
== Rationale ==<br />
Many users want to be able to guarantee that code will not allocate using the GC.<br />
<br />
== Description ==<br />
@nogc goes in the same way that the nothrow attribute does, and is quite similar in behavior.<br />
It affects inheritance in that it is covariant.<br />
The name mangling for it will be "Ni".<br />
@nogc will be inferred for template functions in the same manner as nothrow is.<br />
@nogc will be transitive, in that all functions called by an @nogc function must also be @nogc.<br />
GC allocations in a @nogc function will be disallowed, and that means calls to<br />
operator new, closures that allocate on the GC, array concatenation, array appends, and some array literals.<br />
<br />
No functions in the GC implementation will be marked @nogc.<br />
<br />
== Usage ==<br />
<br />
@nogc int func(int a) { ... }<br />
<br />
== Static allocations should be ignored ==<br />
<br />
This code (and its mutable __gshared variants) should work since the beginning:<br />
<br />
void foo() @nogc nothrow {<br />
static const err = new Error("error");<br />
throw err;<br />
}<br />
<br />
The situation is similar to this code, that is allowed (text is not nothrow, but here it's called at compile-time):<br />
<br />
void foo() nothrow {<br />
import std.conv;<br />
enum msg = text(10);<br />
}<br />
<br />
== Behaviour in presence of optimizations ==<br />
<br />
Using Escape Analysis the LDC2 compiler is able to remove the heap allocation from this main function when full optimizations are used. However, validity of code should not be affected by optimization settings. (Nor can it be, without intertwining the compiler front-end with each back-end in rather complicated ways.) Hence the following main function cannot be annotated with @nogc even when Escape Analysis removes the heap allocation:<br />
<br />
__gshared int x = 5;<br />
int main() {<br />
int[] a = [x, x + 10, x * x];<br />
return a[0] + a[1] + a[2];<br />
}<br />
<br />
In a successive development phase of @nogc we can perhaps relax some of its strictness introducing some standard (required by all conformant D compilers and performed at all optimization levels) common cases of escape analysis, that allow to use @nogc annotations in more cases, perhaps also like the one above. One possible disadvantage of this idea is that such escape analysis could slow down a little all D compilations, even the fastest debug builds.<br />
<br />
== Copyright ==<br />
This document has been placed in the Public Domain.<br />
<br />
[[Category: DIP]]</div>
Bearophile
https://wiki.dlang.org/?title=DIP60&diff=4045
DIP60
2014-04-18T01:04:42Z
<p>Bearophile: Added a note regarding the behaviour of @nogc in presence of optimizations. Please remove it if the note is wrong.</p>
<hr />
<div>{| class="wikitable"<br />
!Title:<br />
!'''DIP Add @nogc Function Attribute'''<br />
|-<br />
|DIP:<br />
|60<br />
|-<br />
|Version:<br />
|1.2<br />
|-<br />
|Status:<br />
|Draft<br />
|-<br />
|Created:<br />
|2014-4-15<br />
|-<br />
|Last Modified:<br />
|2014-4-18<br />
|-<br />
|Author:<br />
|Walter Bright<br />
|-<br />
|Links:<br />
|[[DIP60/Archive]] — [https://github.com/D-Programming-Language/dmd/pull/3455 pull request]<br />
- [http://forum.dlang.org/post/lijoli$2jma$1@digitalmars.com forum discussion]<br />
|}<br />
<br />
== Abstract ==<br />
The @nogc function attribute will mark a function as not making any allocations using the GC.<br />
<br />
== Rationale ==<br />
Many users want to be able to guarantee that code will not allocate using the GC.<br />
<br />
== Description ==<br />
@nogc goes in the same way that the nothrow attribute does, and is quite similar in behavior.<br />
It affects inheritance in that it is covariant.<br />
The name mangling for it will be "Ni".<br />
@nogc will be inferred for template functions in the same manner as nothrow is.<br />
@nogc will be transitive, in that all functions called by an @nogc function must also be @nogc.<br />
GC allocations in a @nogc function will be disallowed, and that means calls to<br />
operator new, closures that allocate on the GC, array concatenation, array appends, and some array literals.<br />
<br />
No functions in the GC implementation will be marked @nogc.<br />
<br />
== Usage ==<br />
<br />
@nogc int func(int a) { ... }<br />
<br />
== Static allocations should be ignored ==<br />
<br />
This code (and its mutable __gshared variants) should work since the beginning:<br />
<br />
void foo() @nogc nothrow {<br />
static const err = new Error("error");<br />
throw err;<br />
}<br />
<br />
The situation is similar to this code, that is allowed (text is not nothrow, but here it's called at compile-time):<br />
<br />
void foo() nothrow {<br />
import std.conv;<br />
enum msg = text(10);<br />
}<br />
<br />
== Behaviour in presence of optimizations ==<br />
<br />
Using Escape Analysis the LDC2 compiler is able to remove the heap allocation from this main function when full optimizations are used. So it should be possible to annotate this main function with @nogc and compile it successfully when the Escape Analysis removes the heap allocation:<br />
<br />
__gshared int x = 5;<br />
int main() {<br />
int[] a = [x, x + 10, x * x];<br />
return a[0] + a[1] + a[2];<br />
}<br />
<br />
== Copyright ==<br />
This document has been placed in the Public Domain.<br />
<br />
[[Category: DIP]]</div>
Bearophile
https://wiki.dlang.org/?title=DIP60&diff=4044
DIP60
2014-04-16T20:40:36Z
<p>Bearophile: Added a note regarding static allocations.</p>
<hr />
<div>{| class="wikitable"<br />
!Title:<br />
!'''DIP Add @nogc Function Attribute'''<br />
|-<br />
|DIP:<br />
|60<br />
|-<br />
|Version:<br />
|1.1<br />
|-<br />
|Status:<br />
|Draft<br />
|-<br />
|Created:<br />
|2014-4-15<br />
|-<br />
|Last Modified:<br />
|2014-4-16<br />
|-<br />
|Author:<br />
|Walter Bright<br />
|-<br />
|Links:<br />
|[[DIP60/Archive]] — [https://github.com/D-Programming-Language/dmd/pull/3455 pull request]<br />
- [http://forum.dlang.org/post/lijoli$2jma$1@digitalmars.com forum discussion]<br />
|}<br />
<br />
== Abstract ==<br />
The @nogc function attribute will mark a function as not making any allocations using the GC.<br />
<br />
== Rationale ==<br />
Many users want to be able to guarantee that code will not allocate using the GC.<br />
<br />
== Description ==<br />
@nogc goes in the same way that the nothrow attribute does, and is quite similar in behavior.<br />
It affects inheritance in that it is covariant.<br />
The name mangling for it will be "Ni".<br />
@nogc will be inferred for template functions in the same manner as nothrow is.<br />
@nogc will be transitive, in that all functions called by an @nogc function must also be @nogc.<br />
GC allocations in a @nogc function will be disallowed, and that means calls to<br />
operator new, closures that allocate on the GC, array concatenation, array appends, and some array literals.<br />
<br />
No functions in the GC implementation will be marked @nogc.<br />
<br />
== Usage ==<br />
<br />
@nogc int func(int a) { ... }<br />
<br />
== Static allocations should be ignored ==<br />
<br />
This code (and its mutable __gshared variants) should work since the beginning:<br />
<br />
void foo() @nogc nothrow {<br />
static const err = new Error("error");<br />
throw err;<br />
}<br />
<br />
The situation is similar to this code, that is allowed (text is not nothrow, but here it's called at compile-time):<br />
<br />
void foo() nothrow {<br />
import std.conv;<br />
enum msg = text(10);<br />
}<br />
<br />
== Copyright ==<br />
This document has been placed in the Public Domain.<br />
<br />
[[Category: DIP]]</div>
Bearophile
https://wiki.dlang.org/?title=DIP32&diff=2871
DIP32
2013-08-17T00:10:37Z
<p>Bearophile: Added a possible Unicode presentation for the banana syntax</p>
<hr />
<div>== DIP32: Uniform tuple syntax ==<br />
<br />
{| class="wikitable"<br />
!Title: <br />
!'''Uniform tuple syntax'''<br />
|-<br />
|DIP:<br />
|32<br />
|-<br />
|Version:<br />
|1<br />
|-<br />
|Status:<br />
|Draft<br />
|-<br />
|Created:<br />
|2013-03-29<br />
|-<br />
|Last Modified:<br />
|2013-03-29<br />
|-<br />
|Author:<br />
|Hara Kenji<br />
|-<br />
|Links:<br />
|<br />
|}<br />
<br />
== Abstract ==<br />
<br />
This is a proposal for consistent tuple syntax and features.<br />
<br />
== Generic type/expression tuple syntax ==<br />
<br />
Use braces and commas.<br />
Inside tuple literal, <code>;</code> never appears. So it will not be confused with lambdas and ScopeStatements.<br />
<br />
<syntaxhighlight lang="d"><br />
auto tup = {10, "hi", 3.14};<br />
assert(tup[0] == 10); // indexing access<br />
<br />
// In initializers<br />
auto fp = {;}; // lambda<br />
auto dg = {x;}; // lambda<br />
auto tup = {}; // zero-element tuple (Syntax meaning will be changed!)<br />
Struct s = {}; // StructInitializer<br />
<br />
// In function arguments<br />
foo({;}); // lambda<br />
foo({}); // zero-element tuple (Syntax meaning will be changed!)<br />
foo({1}); // one-element tuple<br />
foo({1, "hi"}); // two-element tuple<br />
<br />
// In statements<br />
void test() {<br />
{1, "hi"} // two-element tuple<br />
{1} // one-element tuple<br />
{} // ScopeStatement with no statements, not zero-element tuple.<br />
// {} = tup; // no-side effect assignment.<br />
// {} = tup; // meaningless unpacking & declaration.<br />
// if (true) {} func;<br />
// ScopeStatement and parenthesis-less func call.<br />
}<br />
<br />
// declare tuple value by using explicit tuple type<br />
{int, string} tup = {1, "hi"};<br />
assert(tup[0] == 1);<br />
assert(tup[1] == "hi");<br />
static assert(is(typeof(tup) == {int, string})); // tuple type<br />
<br />
alias TL = {int, string[], double[string]}; // types<br />
alias Fields = {int, "num", int[string], "map"}; // mixing<br />
alias date = {2013, 3, 29}; // values<br />
<br />
foreach (Float; {float, double, real}) { ... }<br />
</syntaxhighlight><br />
<br />
<!--<br />
{int, int, int} d = date; // works, but...<br />
void getDate({int y, int m, int d}) { ... }<br />
getDate( date ); // doesn't work...?<br />
getDate({date}); // works.<br />
--><br />
<br />
== Tuple unpacking and pattern matching ==<br />
<br />
Tuple value unpacking will become handy with help of language syntax.<br />
Also, pattern matching syntax will be allowed in some places.<br />
<br />
=== Various places that you can use unpacking ===<br />
<br />
<ul><br />
<li style="margin-bottom: 1em;"><br />
Variable declaration<br />
<syntaxhighlight lang="d"><br />
auto {x, y} = {1, "hi"};<br />
{auto x, y} = {1, "hi"};<br />
{int x, string y} = {1, "hi"};<br />
assert(x == 1 && y == "hi");<br />
</syntaxhighlight><br />
<br />
<li style="margin-bottom: 1em;"><br />
Left side of assignment expression:<br />
<syntaxhighlight lang="d"><br />
auto tup = {1, "hi"};<br />
int a, string b;<br />
{a, b} = tup; // Rewritten as: a = tup[0], b = tup[1];<br />
{c, $} = tup; // Rewritten as: c = tup[0];<br />
</syntaxhighlight><br />
<br />
<strong>Note:</strong> Cannot swap values by tuple assignment.<br />
<syntaxhighlight lang="d"><br />
int x = 1, y = 2;<br />
{x, y} = {y, x};<br />
// Lowered to:<br />
// x = y, y = x;<br />
assert(y == 2);<br />
assert(x == 2);<br />
</syntaxhighlight><br />
<br />
<li style="margin-bottom: 1em;"><br />
Foreach iteratee<br />
<syntaxhighlight lang="d"><br />
foreach ({x, y}; zip([1,2,3], ["a","b","c"])) {}<br />
foreach (i, const {x, y}; [{1,2}, {3,4}, {5,6}, ...]) {<br />
// i == 0, 1, 2, ...<br />
// {x,y} == {1,2}, {3,4}, {5,6}, ...<br />
}<br />
</syntaxhighlight><br />
<br />
Index of array, key of associative array should not be<br />
included in the pattern. So<br />
<syntaxhighlight lang="d"><br />
foreach ({i, e}; arr) {} // only allowed when arr[n] is two-element tuple<br />
foreach ( i, e ; arr) {} // i captures implicitly given indices<br />
</syntaxhighlight><br />
This is necessary behavior for backward compatibility and disambiguation.<br />
<br />
And, this syntax (currently it is not enough documented)<br />
<syntaxhighlight lang="d"><br />
foreach (x, y; zip([1,2,3], ["a","b","c"])) {}<br />
</syntaxhighlight><br />
should be deprecated.<br />
<br />
If iterated range has ref front, pattern can have ref annotation.<br />
<syntaxhighlight lang="d"><br />
auto nums = [100, 200, 300];<br />
auto strs = ["a", "b", "c"];<br />
foreach (ref {x, y}; zip(nums, arr)) {<br />
x /= 10;<br />
y = x.to!string;<br />
}<br />
assert(nums == [ 10 , 20 , 30 ]);<br />
assert(strs == ["10", "20", "30"]);<br />
</syntaxhighlight><br />
<br />
<li style="margin-bottom: 1em;"><br />
Function parameters:<br />
<syntaxhighlight lang="d"><br />
void foo({int x, long y});<br />
void foo({int, string name}, string msg);<br />
// The first element of the tuple is 'unnamed'.<br />
<br />
// with lambdas:<br />
({A a, B b}) => a + b;<br />
({a, b}) => a + b;<br />
{a, b} => a + b;<br />
</syntaxhighlight><br />
<br />
</ul><br />
<br />
=== Various places that you can use unpacking and pattern matching ===<br />
<br />
<ul><br />
<li style="margin-bottom: 1em;"><br />
<code>if</code> statement with pattern matching<br />
<syntaxhighlight lang="d"><br />
if (auto {1, y} = tup) {<br />
// If the first element of tup (tup[0]) is equal to 1,<br />
// y captures the second element of tup (tup[1]).<br />
}<br />
</syntaxhighlight><br />
<br />
<li style="margin-bottom: 1em;"><br />
<code>case</code> values<br />
<syntaxhighlight lang="d"><br />
switch (tup) {<br />
case {1, 2}:<br />
case {$, 2}:<br />
case {1, x}: // capture tup[1] into 'x' when tup[0] == 1<br />
default: // same as {...}<br />
}<br />
</syntaxhighlight><br />
The cases with patterns will be evaluated in lexical order.<br />
<br />
</ul><br />
<br />
=== Difference between unpacking and pattern matching ===<br />
<br />
Pattern matching is only allowed in <code>if</code> and <code>case</code> statements.<br />
<syntaxhighlight lang="d"><br />
auto coord = {1, 2};<br />
if (auto {1, y} = coord) {} // if statement, ok<br />
switch(coord) { case {1, y}: ...; } // case statement, ok<br />
auto {1, y} = coord; // variable declaration, ng!<br />
</syntaxhighlight><br />
Because the two have conditional statements which is evaluated iff the pattern matches to the operand.<br />
Therefore <code>$identifier</code> is only allowed for the pattern match.<br />
<br />
<dl><br />
<dt><code>...</code> meaning for unpacking<br />
<dd><br />
<code>...</code> is used for the special unpacking placeholder. It matches zero or more elements.<br />
<syntaxhighlight lang="d"><br />
auto tup = {1, "hi", 3.14, [1,2,3]};<br />
if (auto {1, "hi", ...} = tup) {}<br />
</syntaxhighlight><br />
<br />
<dt><code>$</code> meaning for unpacking<br />
<dd><br />
<code>$</code> is used for the special unpacking placeholder for one element but not used. It does not conflict with curent <code>array.length</code> usage, because:<br />
<br />
<ol><br />
<li>all pattern matching is always appeared in statements.<br />
<li>To use statements in array indices, function literal is necessary. But:<br />
<syntaxhighlight lang="d"><br />
int[] a = [1,2,3];<br />
auto x = a[(){ return $-1; }()];<br />
// Error: cannnot use $ inside a function literal<br />
</syntaxhighlight><br />
</ol><br />
<br />
Therefore,<br />
<syntaxhighlight lang="d"><br />
auto x = a[(){<br />
if (auto {1, $} = tup) { // '$' is always *pattern placeholder*<br />
...<br />
}<br />
return 0;<br />
}];<br />
</syntaxhighlight><br />
<br />
<dt><code>$identifier</code> meaning for pattern matching<br />
<dd><br />
$identifier is used for the special syntax for pattern matching.<br />
Inside pattern, bare <code>identifier</code> will always make placeholder.<br />
<syntaxhighlight lang="d"><br />
if (auto {x, y} = coord) {<br />
// x and y captures coord's elements only in 'then' statement.<br />
}<br />
</syntaxhighlight><br />
<br />
If newly declared valiable conflicts with outer variables, it is refused.<br />
<syntaxhighlight lang="d"><br />
int x = 1;<br />
if (auto {x, y} = coord) { auto x2 = x; } // error, ambiguous 'x' usage<br />
</syntaxhighlight><br />
<br />
If you want to make a pattern with evaluating variable, use <code>$identifier</code>.<br />
<syntaxhighlight lang="d"><br />
int x = 1;<br />
if (auto {$x, y} = coord) { ... }<br />
// If the first element of coord is equal to 1 (== x), 'then' statement wil be evaluated.<br />
</syntaxhighlight><br />
<br />
</dl><br />
<br />
=== Unpacking and tuple expansion ===<br />
<br />
Unpacking implicitly requires tuple for its operand, so it can be automatically expanded.<br />
<syntaxhighlight lang="d"><br />
auto coord = {1, 2};<br />
if (auto {x, y} = coord) {}<br />
if (auto {x, y} = coord[]) {} // same, explicitly expands fields<br />
</syntaxhighlight><br />
<br />
=== Mismatching tuple element types and length ===<br />
<br />
<syntaxhighlight lang="d"><br />
auto tup = {1, "hi"}<br />
if (auto {num} = tup) {} // compile error<br />
if (auto {num, msg, x} = tup) {} // compile error<br />
if ({string num, int msg} = tup) {} // compile error<br />
<br />
if (auto {num, msg, ...} = tup) {} // ok, `...` matches to zero-elements.<br />
</syntaxhighlight><br />
<br />
<!--<br />
== TODO ==<br />
<br />
The things written in this section are not yet well defined, so they might be removed later.<br />
<br />
=== Tuple fields are always unnamed ===<br />
<br />
<syntaxhighlight lang="d"><br />
// The types of tuples which have field names<br />
alias MyPair = typeof({1, "hi"});<br />
alias MyRecord = typeof({count:1, msg:"hi"});<br />
static assert(is(MyPair == MyRecord)); // true or false?<br />
static assert(is(MyPair : MyRecord)); // true or false?<br />
static assert(is(MyRecord : MyPair)); // true or false?<br />
alias MyStudent = typeof({num:1, name:"John"});<br />
static assert(is(MyRecord == MyStudent)); // true or false?<br />
<br />
// named pattern is mostly useless<br />
if (auto {num:1, msg:"hi"} = pair) {}<br />
</syntaxhighlight><br />
<br />
=== Unpacking fields from object ===<br />
<br />
<syntaxhighlight lang="d"><br />
auto tup = {obj.a, obj.b, obj.c}<br />
is shorten to:<br />
auto tup = obj.{a, b, c}<br />
<br />
auto tup = {obj.a, obj.b.x, obj.b.y, obj.c}<br />
is shorten to:<br />
auto tup = obj.{a, b.{x, y}[], c}<br />
</syntaxhighlight><br />
<br />
* With `obj.{...}`, can guarantee that `obj` will be evaluated once.<br />
* The result of `obj.{...}` always makes a tuple.<br />
It is essential limitation that comes from the syntax .<br />
--><br />
<br />
== Use case of uniform tuple syntax ==<br />
<br />
Original D code:<br />
Source: http://forum.dlang.org/post/gridjorxqlpoytuxwpsg@forum.dlang.org<br />
<br />
<syntaxhighlight lang="d"><br />
import std.stdio, std.algorithm, std.typecons, std.container, std.array;<br />
<br />
auto encode(T)(Group!("a == b", T[]) sf) {<br />
auto heap = sf.map!(s => tuple(s[1], [tuple(s[0], "")]))<br />
.array.heapify!q{b < a};<br />
<br />
while (heap.length > 1) {<br />
auto lo = heap.front; heap.removeFront;<br />
auto hi = heap.front; heap.removeFront;<br />
foreach (ref pair; lo[1]) pair[1] = '0' ~ pair[1];<br />
foreach (ref pair; hi[1]) pair[1] = '1' ~ pair[1];<br />
heap.insert(tuple(lo[0] + hi[0], lo[1] ~ hi[1]));<br />
}<br />
return heap.front[1].schwartzSort!q{tuple(a[1].length, a[0])};<br />
}<br />
<br />
void main() {<br />
auto s = "this is an example for huffman encoding"d;<br />
foreach (p; s.dup.sort().release.group.encode)<br />
writefln("'%s' %s", p[]);<br />
}<br />
</syntaxhighlight><br />
<br />
<br />
This proposal:<br />
<br />
<syntaxhighlight lang="d"><br />
import std.stdio, std.algorithm, std.container, std.array;<br />
<br />
auto encode(T)(Group!("a == b", T[]) sf) {<br />
auto heap = sf.map!({c, f} => {f, [{c, ""}]}).array.heapify!q{b < a};<br />
<br />
while (heap.length > 1) {<br />
auto {lof, loa} = heap.front; heap.removeFront;<br />
auto {hif, hia} = heap.front; heap.removeFront;<br />
<br />
foreach ({$, ref e}; loa) e = '0' ~ e;<br />
foreach ({$, ref e}; hia) e = '1' ~ e;<br />
heap.insert({lof + hif, loa ~ hia});<br />
}<br />
<br />
return heap.front[1].schwartzSort!({c, e} => {e.length, c});<br />
}<br />
<br />
void main() {<br />
auto s = "this is an example for huffman encoding"d;<br />
foreach ({c, e}; s.dup.sort().release.group.encode)<br />
writefln("'%s' %s", c, e);<br />
}<br />
</syntaxhighlight><br />
<br />
<br />
Basic () syntax, perhaps the cleanest, but can't be used:<br />
<br />
<syntaxhighlight lang="d"><br />
import std.stdio, std.algorithm, std.container, std.array;<br />
<br />
auto encode(T)(Group!("a == b", T[]) sf) {<br />
auto heap = sf.map!((c, f) => (f, [(c, "")])).array.heapify!q{b < a};<br />
<br />
while (heap.length > 1) {<br />
auto (lof, loa) = heap.front; heap.removeFront;<br />
auto (hif, hia) = heap.front; heap.removeFront;<br />
foreach ((_, ref e); loa) e = '0' ~ e;<br />
foreach ((_, ref e); hia) e = '1' ~ e;<br />
heap.insert((lof + hif, loa ~ hia));<br />
}<br />
return heap.front[1].schwartzSort!((c, e) => (e.length, c));<br />
}<br />
<br />
void main() {<br />
auto s = "this is an example for huffman encoding"d;<br />
foreach ((c, e); s.dup.sort().release.group.encode)<br />
writefln("'%s' %s", c, e);<br />
}<br />
</syntaxhighlight><br />
<br />
<br />
tuple() syntax, clear, a bit long:<br />
<br />
<syntaxhighlight lang="d"><br />
import std.stdio, std.algorithm, std.container, std.array;<br />
<br />
auto encode(T)(Group!("a == b", T[]) sf) {<br />
auto heap = sf.map!(tuple(c, f) => tuple(f, [tuple(c, "")]))<br />
.array.heapify!q{b < a};<br />
<br />
while (heap.length > 1) {<br />
auto tuple(lof, loa) = heap.front; heap.removeFront;<br />
auto tuple(hif, hia) = heap.front; heap.removeFront;<br />
foreach (tuple(_, ref e); loa) e = '0' ~ e;<br />
foreach (tuple(_, ref e); hia) e = '1' ~ e;<br />
heap.insert(tuple(lof + hif, loa ~ hia));<br />
}<br />
return heap.front[1].schwartzSort!(tuple(c, e) => tuple(e.length, c));<br />
}<br />
<br />
void main() {<br />
auto s = "this is an example for huffman encoding"d;<br />
foreach (tuple(c, e); s.dup.sort().release.group.encode)<br />
writefln("'%s' %s", c, e);<br />
}<br />
</syntaxhighlight><br />
<br />
<br />
@{} syntax, noisy:<br />
<br />
<syntaxhighlight lang="d"><br />
import std.stdio, std.algorithm, std.container, std.array;<br />
<br />
auto encode(T)(Group!("a == b", T[]) sf) {<br />
auto heap = sf.map!(@{c, f} => {f, [@{c, ""}]}).array.heapify!q{b < a};<br />
<br />
while (heap.length > 1) {<br />
auto @{lof, loa} = heap.front; heap.removeFront;<br />
auto @{hif, hia} = heap.front; heap.removeFront;<br />
foreach (@{_, ref e}; loa) e = '0' ~ e;<br />
foreach (@{_, ref e}; hia) e = '1' ~ e;<br />
heap.insert(@{lof + hif, loa ~ hia});<br />
}<br />
return heap.front[1].schwartzSort!(@{c, e} => @{e.length, c});<br />
}<br />
<br />
void main() {<br />
auto s = "this is an example for huffman encoding"d;<br />
foreach (@{c, e}; s.dup.sort().release.group.encode)<br />
writefln("'%s' %s", c, e);<br />
}<br />
</syntaxhighlight><br />
<br />
<br />
<br />
(||) banana syntax, a bit confusing, but IDEs can visualize (| and |) as some nice Unicode glyps:<br />
<br />
<syntaxhighlight lang="d"><br />
import std.stdio, std.algorithm, std.container, std.array;<br />
<br />
auto encode(T)(Group!("a == b", T[]) sf) {<br />
auto heap = sf.map!((|c, f|) => (|f, [(|c, ""|)]|)).array.heapify!q{b < a};<br />
<br />
while (heap.length > 1) {<br />
auto (|lof, loa|) = heap.front; heap.removeFront;<br />
auto (|hif, hia|) = heap.front; heap.removeFront;<br />
foreach ((|_, ref e|); loa) e = '0' ~ e;<br />
foreach ((|_, ref e|); hia) e = '1' ~ e;<br />
heap.insert((|lof + hif, loa ~ hia|));<br />
}<br />
return heap.front[1].schwartzSort!((|c, e|) => (|e.length, c|));<br />
}<br />
<br />
void main() {<br />
auto s = "this is an example for huffman encoding"d;<br />
foreach ((|c, e|); s.dup.sort().release.group.encode)<br />
writefln("'%s' %s", c, e);<br />
}<br />
</syntaxhighlight><br />
<br />
Something like:<br />
<syntaxhighlight lang="d"><br />
import std.stdio, std.algorithm, std.container, std.array;<br />
<br />
auto encode(T)(Group!("a == b", T[]) sf) {<br />
auto heap = sf.map!(⦅c, f⦆ => ⦅f, [⦅c, ""⦆]⦆).array.heapify!q{b < a};<br />
<br />
while (heap.length > 1) {<br />
auto ⦅lof, loa⦆ = heap.front; heap.removeFront;<br />
auto ⦅hif, hia⦆ = heap.front; heap.removeFront;<br />
foreach (⦅_, ref e⦆; loa) e = '0' ~ e;<br />
foreach (⦅_, ref e⦆; hia) e = '1' ~ e;<br />
heap.insert(⦅lof + hif, loa ~ hia⦆);<br />
}<br />
return heap.front[1].schwartzSort!(⦅c, e⦆ => ⦅e.length, c⦆);<br />
}<br />
<br />
void main() {<br />
auto s = "this is an example for huffman encoding"d;<br />
foreach (⦅c, e⦆; s.dup.sort().release.group.encode)<br />
writefln("'%s' %s", c, e);<br />
}<br />
</syntaxhighlight><br />
<br />
<br />
t{} syntax, the t is not very easy to see, but it's short and it's similar to the q{} for token strings:<br />
<br />
<syntaxhighlight lang="d"><br />
import std.stdio, std.algorithm, std.container, std.array;<br />
<br />
auto encode(T)(Group!("a == b", T[]) sf) {<br />
auto heap = sf.map!(t{c, f} => {f, [t{c, ""}]}).array.heapify!q{b < a};<br />
<br />
while (heap.length > 1) {<br />
auto t{lof, loa} = heap.front; heap.removeFront;<br />
auto t{hif, hia} = heap.front; heap.removeFront;<br />
foreach (t{_, ref e}; loa) e = '0' ~ e;<br />
foreach (t{_, ref e}; hia) e = '1' ~ e;<br />
heap.insert(t{lof + hif, loa ~ hia});<br />
}<br />
return heap.front[1].schwartzSort!(t{c, e} => t{e.length, c});<br />
}<br />
<br />
void main() {<br />
auto s = "this is an example for huffman encoding"d;<br />
foreach (t{c, e}; s.dup.sort().release.group.encode)<br />
writefln("'%s' %s", c, e);<br />
}<br />
</syntaxhighlight><br />
<br />
<br />
<code>#()</code> syntax (suggested by Meta), short, not too much noisy, and it's visually searchable and popping more than t{}:<br />
<br />
<syntaxhighlight lang="d"><br />
import std.stdio, std.algorithm, std.container, std.array;<br />
<br />
auto encode(T)(Group!("a == b", T[]) sf) {<br />
auto heap = sf.map!(#(c, f) => #(f, [#(c, "")])).array.heapify!q{b < a};<br />
<br />
while (heap.length > 1) {<br />
auto #(lof, loa) = heap.front; heap.removeFront;<br />
auto #(hif, hia) = heap.front; heap.removeFront;<br />
foreach (#(_, ref e); loa) e = '0' ~ e;<br />
foreach (#(_, ref e); hia) e = '1' ~ e;<br />
heap.insert(#(lof + hif, loa ~ hia));<br />
}<br />
return heap.front[1].schwartzSort!(#(c, e) => #(e.length, c));<br />
}<br />
<br />
void main() {<br />
auto s = "this is an example for huffman encoding"d;<br />
foreach (#(c, e); s.dup.sort().release.group.encode)<br />
writefln("'%s' %s", c, e);<br />
}<br />
</syntaxhighlight><br />
<br />
== Copyright ==<br />
<br />
This document has been placed in the Public Domain.</div>
Bearophile
https://wiki.dlang.org/?title=DIP32&diff=2870
DIP32
2013-08-17T00:01:40Z
<p>Bearophile: Undo revision 2869 by Bearophile (talk)</p>
<hr />
<div>== DIP32: Uniform tuple syntax ==<br />
<br />
{| class="wikitable"<br />
!Title: <br />
!'''Uniform tuple syntax'''<br />
|-<br />
|DIP:<br />
|32<br />
|-<br />
|Version:<br />
|1<br />
|-<br />
|Status:<br />
|Draft<br />
|-<br />
|Created:<br />
|2013-03-29<br />
|-<br />
|Last Modified:<br />
|2013-03-29<br />
|-<br />
|Author:<br />
|Hara Kenji<br />
|-<br />
|Links:<br />
|<br />
|}<br />
<br />
== Abstract ==<br />
<br />
This is a proposal for consistent tuple syntax and features.<br />
<br />
== Generic type/expression tuple syntax ==<br />
<br />
Use braces and commas.<br />
Inside tuple literal, <code>;</code> never appears. So it will not be confused with lambdas and ScopeStatements.<br />
<br />
<syntaxhighlight lang="d"><br />
auto tup = {10, "hi", 3.14};<br />
assert(tup[0] == 10); // indexing access<br />
<br />
// In initializers<br />
auto fp = {;}; // lambda<br />
auto dg = {x;}; // lambda<br />
auto tup = {}; // zero-element tuple (Syntax meaning will be changed!)<br />
Struct s = {}; // StructInitializer<br />
<br />
// In function arguments<br />
foo({;}); // lambda<br />
foo({}); // zero-element tuple (Syntax meaning will be changed!)<br />
foo({1}); // one-element tuple<br />
foo({1, "hi"}); // two-element tuple<br />
<br />
// In statements<br />
void test() {<br />
{1, "hi"} // two-element tuple<br />
{1} // one-element tuple<br />
{} // ScopeStatement with no statements, not zero-element tuple.<br />
// {} = tup; // no-side effect assignment.<br />
// {} = tup; // meaningless unpacking & declaration.<br />
// if (true) {} func;<br />
// ScopeStatement and parenthesis-less func call.<br />
}<br />
<br />
// declare tuple value by using explicit tuple type<br />
{int, string} tup = {1, "hi"};<br />
assert(tup[0] == 1);<br />
assert(tup[1] == "hi");<br />
static assert(is(typeof(tup) == {int, string})); // tuple type<br />
<br />
alias TL = {int, string[], double[string]}; // types<br />
alias Fields = {int, "num", int[string], "map"}; // mixing<br />
alias date = {2013, 3, 29}; // values<br />
<br />
foreach (Float; {float, double, real}) { ... }<br />
</syntaxhighlight><br />
<br />
<!--<br />
{int, int, int} d = date; // works, but...<br />
void getDate({int y, int m, int d}) { ... }<br />
getDate( date ); // doesn't work...?<br />
getDate({date}); // works.<br />
--><br />
<br />
== Tuple unpacking and pattern matching ==<br />
<br />
Tuple value unpacking will become handy with help of language syntax.<br />
Also, pattern matching syntax will be allowed in some places.<br />
<br />
=== Various places that you can use unpacking ===<br />
<br />
<ul><br />
<li style="margin-bottom: 1em;"><br />
Variable declaration<br />
<syntaxhighlight lang="d"><br />
auto {x, y} = {1, "hi"};<br />
{auto x, y} = {1, "hi"};<br />
{int x, string y} = {1, "hi"};<br />
assert(x == 1 && y == "hi");<br />
</syntaxhighlight><br />
<br />
<li style="margin-bottom: 1em;"><br />
Left side of assignment expression:<br />
<syntaxhighlight lang="d"><br />
auto tup = {1, "hi"};<br />
int a, string b;<br />
{a, b} = tup; // Rewritten as: a = tup[0], b = tup[1];<br />
{c, $} = tup; // Rewritten as: c = tup[0];<br />
</syntaxhighlight><br />
<br />
<strong>Note:</strong> Cannot swap values by tuple assignment.<br />
<syntaxhighlight lang="d"><br />
int x = 1, y = 2;<br />
{x, y} = {y, x};<br />
// Lowered to:<br />
// x = y, y = x;<br />
assert(y == 2);<br />
assert(x == 2);<br />
</syntaxhighlight><br />
<br />
<li style="margin-bottom: 1em;"><br />
Foreach iteratee<br />
<syntaxhighlight lang="d"><br />
foreach ({x, y}; zip([1,2,3], ["a","b","c"])) {}<br />
foreach (i, const {x, y}; [{1,2}, {3,4}, {5,6}, ...]) {<br />
// i == 0, 1, 2, ...<br />
// {x,y} == {1,2}, {3,4}, {5,6}, ...<br />
}<br />
</syntaxhighlight><br />
<br />
Index of array, key of associative array should not be<br />
included in the pattern. So<br />
<syntaxhighlight lang="d"><br />
foreach ({i, e}; arr) {} // only allowed when arr[n] is two-element tuple<br />
foreach ( i, e ; arr) {} // i captures implicitly given indices<br />
</syntaxhighlight><br />
This is necessary behavior for backward compatibility and disambiguation.<br />
<br />
And, this syntax (currently it is not enough documented)<br />
<syntaxhighlight lang="d"><br />
foreach (x, y; zip([1,2,3], ["a","b","c"])) {}<br />
</syntaxhighlight><br />
should be deprecated.<br />
<br />
If iterated range has ref front, pattern can have ref annotation.<br />
<syntaxhighlight lang="d"><br />
auto nums = [100, 200, 300];<br />
auto strs = ["a", "b", "c"];<br />
foreach (ref {x, y}; zip(nums, arr)) {<br />
x /= 10;<br />
y = x.to!string;<br />
}<br />
assert(nums == [ 10 , 20 , 30 ]);<br />
assert(strs == ["10", "20", "30"]);<br />
</syntaxhighlight><br />
<br />
<li style="margin-bottom: 1em;"><br />
Function parameters:<br />
<syntaxhighlight lang="d"><br />
void foo({int x, long y});<br />
void foo({int, string name}, string msg);<br />
// The first element of the tuple is 'unnamed'.<br />
<br />
// with lambdas:<br />
({A a, B b}) => a + b;<br />
({a, b}) => a + b;<br />
{a, b} => a + b;<br />
</syntaxhighlight><br />
<br />
</ul><br />
<br />
=== Various places that you can use unpacking and pattern matching ===<br />
<br />
<ul><br />
<li style="margin-bottom: 1em;"><br />
<code>if</code> statement with pattern matching<br />
<syntaxhighlight lang="d"><br />
if (auto {1, y} = tup) {<br />
// If the first element of tup (tup[0]) is equal to 1,<br />
// y captures the second element of tup (tup[1]).<br />
}<br />
</syntaxhighlight><br />
<br />
<li style="margin-bottom: 1em;"><br />
<code>case</code> values<br />
<syntaxhighlight lang="d"><br />
switch (tup) {<br />
case {1, 2}:<br />
case {$, 2}:<br />
case {1, x}: // capture tup[1] into 'x' when tup[0] == 1<br />
default: // same as {...}<br />
}<br />
</syntaxhighlight><br />
The cases with patterns will be evaluated in lexical order.<br />
<br />
</ul><br />
<br />
=== Difference between unpacking and pattern matching ===<br />
<br />
Pattern matching is only allowed in <code>if</code> and <code>case</code> statements.<br />
<syntaxhighlight lang="d"><br />
auto coord = {1, 2};<br />
if (auto {1, y} = coord) {} // if statement, ok<br />
switch(coord) { case {1, y}: ...; } // case statement, ok<br />
auto {1, y} = coord; // variable declaration, ng!<br />
</syntaxhighlight><br />
Because the two have conditional statements which is evaluated iff the pattern matches to the operand.<br />
Therefore <code>$identifier</code> is only allowed for the pattern match.<br />
<br />
<dl><br />
<dt><code>...</code> meaning for unpacking<br />
<dd><br />
<code>...</code> is used for the special unpacking placeholder. It matches zero or more elements.<br />
<syntaxhighlight lang="d"><br />
auto tup = {1, "hi", 3.14, [1,2,3]};<br />
if (auto {1, "hi", ...} = tup) {}<br />
</syntaxhighlight><br />
<br />
<dt><code>$</code> meaning for unpacking<br />
<dd><br />
<code>$</code> is used for the special unpacking placeholder for one element but not used. It does not conflict with curent <code>array.length</code> usage, because:<br />
<br />
<ol><br />
<li>all pattern matching is always appeared in statements.<br />
<li>To use statements in array indices, function literal is necessary. But:<br />
<syntaxhighlight lang="d"><br />
int[] a = [1,2,3];<br />
auto x = a[(){ return $-1; }()];<br />
// Error: cannnot use $ inside a function literal<br />
</syntaxhighlight><br />
</ol><br />
<br />
Therefore,<br />
<syntaxhighlight lang="d"><br />
auto x = a[(){<br />
if (auto {1, $} = tup) { // '$' is always *pattern placeholder*<br />
...<br />
}<br />
return 0;<br />
}];<br />
</syntaxhighlight><br />
<br />
<dt><code>$identifier</code> meaning for pattern matching<br />
<dd><br />
$identifier is used for the special syntax for pattern matching.<br />
Inside pattern, bare <code>identifier</code> will always make placeholder.<br />
<syntaxhighlight lang="d"><br />
if (auto {x, y} = coord) {<br />
// x and y captures coord's elements only in 'then' statement.<br />
}<br />
</syntaxhighlight><br />
<br />
If newly declared valiable conflicts with outer variables, it is refused.<br />
<syntaxhighlight lang="d"><br />
int x = 1;<br />
if (auto {x, y} = coord) { auto x2 = x; } // error, ambiguous 'x' usage<br />
</syntaxhighlight><br />
<br />
If you want to make a pattern with evaluating variable, use <code>$identifier</code>.<br />
<syntaxhighlight lang="d"><br />
int x = 1;<br />
if (auto {$x, y} = coord) { ... }<br />
// If the first element of coord is equal to 1 (== x), 'then' statement wil be evaluated.<br />
</syntaxhighlight><br />
<br />
</dl><br />
<br />
=== Unpacking and tuple expansion ===<br />
<br />
Unpacking implicitly requires tuple for its operand, so it can be automatically expanded.<br />
<syntaxhighlight lang="d"><br />
auto coord = {1, 2};<br />
if (auto {x, y} = coord) {}<br />
if (auto {x, y} = coord[]) {} // same, explicitly expands fields<br />
</syntaxhighlight><br />
<br />
=== Mismatching tuple element types and length ===<br />
<br />
<syntaxhighlight lang="d"><br />
auto tup = {1, "hi"}<br />
if (auto {num} = tup) {} // compile error<br />
if (auto {num, msg, x} = tup) {} // compile error<br />
if ({string num, int msg} = tup) {} // compile error<br />
<br />
if (auto {num, msg, ...} = tup) {} // ok, `...` matches to zero-elements.<br />
</syntaxhighlight><br />
<br />
<!--<br />
== TODO ==<br />
<br />
The things written in this section are not yet well defined, so they might be removed later.<br />
<br />
=== Tuple fields are always unnamed ===<br />
<br />
<syntaxhighlight lang="d"><br />
// The types of tuples which have field names<br />
alias MyPair = typeof({1, "hi"});<br />
alias MyRecord = typeof({count:1, msg:"hi"});<br />
static assert(is(MyPair == MyRecord)); // true or false?<br />
static assert(is(MyPair : MyRecord)); // true or false?<br />
static assert(is(MyRecord : MyPair)); // true or false?<br />
alias MyStudent = typeof({num:1, name:"John"});<br />
static assert(is(MyRecord == MyStudent)); // true or false?<br />
<br />
// named pattern is mostly useless<br />
if (auto {num:1, msg:"hi"} = pair) {}<br />
</syntaxhighlight><br />
<br />
=== Unpacking fields from object ===<br />
<br />
<syntaxhighlight lang="d"><br />
auto tup = {obj.a, obj.b, obj.c}<br />
is shorten to:<br />
auto tup = obj.{a, b, c}<br />
<br />
auto tup = {obj.a, obj.b.x, obj.b.y, obj.c}<br />
is shorten to:<br />
auto tup = obj.{a, b.{x, y}[], c}<br />
</syntaxhighlight><br />
<br />
* With `obj.{...}`, can guarantee that `obj` will be evaluated once.<br />
* The result of `obj.{...}` always makes a tuple.<br />
It is essential limitation that comes from the syntax .<br />
--><br />
<br />
== Use case of uniform tuple syntax ==<br />
<br />
Original D code:<br />
Source: http://forum.dlang.org/post/gridjorxqlpoytuxwpsg@forum.dlang.org<br />
<br />
<syntaxhighlight lang="d"><br />
import std.stdio, std.algorithm, std.typecons, std.container, std.array;<br />
<br />
auto encode(T)(Group!("a == b", T[]) sf) {<br />
auto heap = sf.map!(s => tuple(s[1], [tuple(s[0], "")]))<br />
.array.heapify!q{b < a};<br />
<br />
while (heap.length > 1) {<br />
auto lo = heap.front; heap.removeFront;<br />
auto hi = heap.front; heap.removeFront;<br />
foreach (ref pair; lo[1]) pair[1] = '0' ~ pair[1];<br />
foreach (ref pair; hi[1]) pair[1] = '1' ~ pair[1];<br />
heap.insert(tuple(lo[0] + hi[0], lo[1] ~ hi[1]));<br />
}<br />
return heap.front[1].schwartzSort!q{tuple(a[1].length, a[0])};<br />
}<br />
<br />
void main() {<br />
auto s = "this is an example for huffman encoding"d;<br />
foreach (p; s.dup.sort().release.group.encode)<br />
writefln("'%s' %s", p[]);<br />
}<br />
</syntaxhighlight><br />
<br />
<br />
This proposal:<br />
<br />
<syntaxhighlight lang="d"><br />
import std.stdio, std.algorithm, std.container, std.array;<br />
<br />
auto encode(T)(Group!("a == b", T[]) sf) {<br />
auto heap = sf.map!({c, f} => {f, [{c, ""}]}).array.heapify!q{b < a};<br />
<br />
while (heap.length > 1) {<br />
auto {lof, loa} = heap.front; heap.removeFront;<br />
auto {hif, hia} = heap.front; heap.removeFront;<br />
<br />
foreach ({$, ref e}; loa) e = '0' ~ e;<br />
foreach ({$, ref e}; hia) e = '1' ~ e;<br />
heap.insert({lof + hif, loa ~ hia});<br />
}<br />
<br />
return heap.front[1].schwartzSort!({c, e} => {e.length, c});<br />
}<br />
<br />
void main() {<br />
auto s = "this is an example for huffman encoding"d;<br />
foreach ({c, e}; s.dup.sort().release.group.encode)<br />
writefln("'%s' %s", c, e);<br />
}<br />
</syntaxhighlight><br />
<br />
<br />
Basic () syntax, perhaps the cleanest, but can't be used:<br />
<br />
<syntaxhighlight lang="d"><br />
import std.stdio, std.algorithm, std.container, std.array;<br />
<br />
auto encode(T)(Group!("a == b", T[]) sf) {<br />
auto heap = sf.map!((c, f) => (f, [(c, "")])).array.heapify!q{b < a};<br />
<br />
while (heap.length > 1) {<br />
auto (lof, loa) = heap.front; heap.removeFront;<br />
auto (hif, hia) = heap.front; heap.removeFront;<br />
foreach ((_, ref e); loa) e = '0' ~ e;<br />
foreach ((_, ref e); hia) e = '1' ~ e;<br />
heap.insert((lof + hif, loa ~ hia));<br />
}<br />
return heap.front[1].schwartzSort!((c, e) => (e.length, c));<br />
}<br />
<br />
void main() {<br />
auto s = "this is an example for huffman encoding"d;<br />
foreach ((c, e); s.dup.sort().release.group.encode)<br />
writefln("'%s' %s", c, e);<br />
}<br />
</syntaxhighlight><br />
<br />
<br />
tuple() syntax, clear, a bit long:<br />
<br />
<syntaxhighlight lang="d"><br />
import std.stdio, std.algorithm, std.container, std.array;<br />
<br />
auto encode(T)(Group!("a == b", T[]) sf) {<br />
auto heap = sf.map!(tuple(c, f) => tuple(f, [tuple(c, "")]))<br />
.array.heapify!q{b < a};<br />
<br />
while (heap.length > 1) {<br />
auto tuple(lof, loa) = heap.front; heap.removeFront;<br />
auto tuple(hif, hia) = heap.front; heap.removeFront;<br />
foreach (tuple(_, ref e); loa) e = '0' ~ e;<br />
foreach (tuple(_, ref e); hia) e = '1' ~ e;<br />
heap.insert(tuple(lof + hif, loa ~ hia));<br />
}<br />
return heap.front[1].schwartzSort!(tuple(c, e) => tuple(e.length, c));<br />
}<br />
<br />
void main() {<br />
auto s = "this is an example for huffman encoding"d;<br />
foreach (tuple(c, e); s.dup.sort().release.group.encode)<br />
writefln("'%s' %s", c, e);<br />
}<br />
</syntaxhighlight><br />
<br />
<br />
@{} syntax, noisy:<br />
<br />
<syntaxhighlight lang="d"><br />
import std.stdio, std.algorithm, std.container, std.array;<br />
<br />
auto encode(T)(Group!("a == b", T[]) sf) {<br />
auto heap = sf.map!(@{c, f} => {f, [@{c, ""}]}).array.heapify!q{b < a};<br />
<br />
while (heap.length > 1) {<br />
auto @{lof, loa} = heap.front; heap.removeFront;<br />
auto @{hif, hia} = heap.front; heap.removeFront;<br />
foreach (@{_, ref e}; loa) e = '0' ~ e;<br />
foreach (@{_, ref e}; hia) e = '1' ~ e;<br />
heap.insert(@{lof + hif, loa ~ hia});<br />
}<br />
return heap.front[1].schwartzSort!(@{c, e} => @{e.length, c});<br />
}<br />
<br />
void main() {<br />
auto s = "this is an example for huffman encoding"d;<br />
foreach (@{c, e}; s.dup.sort().release.group.encode)<br />
writefln("'%s' %s", c, e);<br />
}<br />
</syntaxhighlight><br />
<br />
<br />
<br />
(||) banana syntax, a bit confusing, but IDEs can visualize (| and |) as some nice Unicode glyps:<br />
<br />
<syntaxhighlight lang="d"><br />
import std.stdio, std.algorithm, std.container, std.array;<br />
<br />
auto encode(T)(Group!("a == b", T[]) sf) {<br />
auto heap = sf.map!((|c, f|) => (|f, [(|c, ""|)]|)).array.heapify!q{b < a};<br />
<br />
while (heap.length > 1) {<br />
auto (|lof, loa|) = heap.front; heap.removeFront;<br />
auto (|hif, hia|) = heap.front; heap.removeFront;<br />
foreach ((|_, ref e|); loa) e = '0' ~ e;<br />
foreach ((|_, ref e|); hia) e = '1' ~ e;<br />
heap.insert((|lof + hif, loa ~ hia|));<br />
}<br />
return heap.front[1].schwartzSort!((|c, e|) => (|e.length, c|));<br />
}<br />
<br />
void main() {<br />
auto s = "this is an example for huffman encoding"d;<br />
foreach ((|c, e|); s.dup.sort().release.group.encode)<br />
writefln("'%s' %s", c, e);<br />
}<br />
</syntaxhighlight><br />
<br />
<br />
t{} syntax, the t is not very easy to see, but it's short and it's similar to the q{} for token strings:<br />
<br />
<syntaxhighlight lang="d"><br />
import std.stdio, std.algorithm, std.container, std.array;<br />
<br />
auto encode(T)(Group!("a == b", T[]) sf) {<br />
auto heap = sf.map!(t{c, f} => {f, [t{c, ""}]}).array.heapify!q{b < a};<br />
<br />
while (heap.length > 1) {<br />
auto t{lof, loa} = heap.front; heap.removeFront;<br />
auto t{hif, hia} = heap.front; heap.removeFront;<br />
foreach (t{_, ref e}; loa) e = '0' ~ e;<br />
foreach (t{_, ref e}; hia) e = '1' ~ e;<br />
heap.insert(t{lof + hif, loa ~ hia});<br />
}<br />
return heap.front[1].schwartzSort!(t{c, e} => t{e.length, c});<br />
}<br />
<br />
void main() {<br />
auto s = "this is an example for huffman encoding"d;<br />
foreach (t{c, e}; s.dup.sort().release.group.encode)<br />
writefln("'%s' %s", c, e);<br />
}<br />
</syntaxhighlight><br />
<br />
<br />
<code>#()</code> syntax (suggested by Meta), short, not too much noisy, and it's visually searchable and popping more than t{}:<br />
<br />
<syntaxhighlight lang="d"><br />
import std.stdio, std.algorithm, std.container, std.array;<br />
<br />
auto encode(T)(Group!("a == b", T[]) sf) {<br />
auto heap = sf.map!(#(c, f) => #(f, [#(c, "")])).array.heapify!q{b < a};<br />
<br />
while (heap.length > 1) {<br />
auto #(lof, loa) = heap.front; heap.removeFront;<br />
auto #(hif, hia) = heap.front; heap.removeFront;<br />
foreach (#(_, ref e); loa) e = '0' ~ e;<br />
foreach (#(_, ref e); hia) e = '1' ~ e;<br />
heap.insert(#(lof + hif, loa ~ hia));<br />
}<br />
return heap.front[1].schwartzSort!(#(c, e) => #(e.length, c));<br />
}<br />
<br />
void main() {<br />
auto s = "this is an example for huffman encoding"d;<br />
foreach (#(c, e); s.dup.sort().release.group.encode)<br />
writefln("'%s' %s", c, e);<br />
}<br />
</syntaxhighlight><br />
<br />
== Copyright ==<br />
<br />
This document has been placed in the Public Domain.</div>
Bearophile
https://wiki.dlang.org/?title=DIP32&diff=2869
DIP32
2013-08-16T23:58:56Z
<p>Bearophile: /* Use case of uniform tuple syntax */</p>
<hr />
<div>== DIP32: Uniform tuple syntax ==<br />
<br />
{| class="wikitable"<br />
!Title: <br />
!'''Uniform tuple syntax'''<br />
|-<br />
|DIP:<br />
|32<br />
|-<br />
|Version:<br />
|1<br />
|-<br />
|Status:<br />
|Draft<br />
|-<br />
|Created:<br />
|2013-03-29<br />
|-<br />
|Last Modified:<br />
|2013-03-29<br />
|-<br />
|Author:<br />
|Hara Kenji<br />
|-<br />
|Links:<br />
|<br />
|}<br />
<br />
== Abstract ==<br />
<br />
This is a proposal for consistent tuple syntax and features.<br />
<br />
== Generic type/expression tuple syntax ==<br />
<br />
Use braces and commas.<br />
Inside tuple literal, <code>;</code> never appears. So it will not be confused with lambdas and ScopeStatements.<br />
<br />
<syntaxhighlight lang="d"><br />
auto tup = {10, "hi", 3.14};<br />
assert(tup[0] == 10); // indexing access<br />
<br />
// In initializers<br />
auto fp = {;}; // lambda<br />
auto dg = {x;}; // lambda<br />
auto tup = {}; // zero-element tuple (Syntax meaning will be changed!)<br />
Struct s = {}; // StructInitializer<br />
<br />
// In function arguments<br />
foo({;}); // lambda<br />
foo({}); // zero-element tuple (Syntax meaning will be changed!)<br />
foo({1}); // one-element tuple<br />
foo({1, "hi"}); // two-element tuple<br />
<br />
// In statements<br />
void test() {<br />
{1, "hi"} // two-element tuple<br />
{1} // one-element tuple<br />
{} // ScopeStatement with no statements, not zero-element tuple.<br />
// {} = tup; // no-side effect assignment.<br />
// {} = tup; // meaningless unpacking & declaration.<br />
// if (true) {} func;<br />
// ScopeStatement and parenthesis-less func call.<br />
}<br />
<br />
// declare tuple value by using explicit tuple type<br />
{int, string} tup = {1, "hi"};<br />
assert(tup[0] == 1);<br />
assert(tup[1] == "hi");<br />
static assert(is(typeof(tup) == {int, string})); // tuple type<br />
<br />
alias TL = {int, string[], double[string]}; // types<br />
alias Fields = {int, "num", int[string], "map"}; // mixing<br />
alias date = {2013, 3, 29}; // values<br />
<br />
foreach (Float; {float, double, real}) { ... }<br />
</syntaxhighlight><br />
<br />
<!--<br />
{int, int, int} d = date; // works, but...<br />
void getDate({int y, int m, int d}) { ... }<br />
getDate( date ); // doesn't work...?<br />
getDate({date}); // works.<br />
--><br />
<br />
== Tuple unpacking and pattern matching ==<br />
<br />
Tuple value unpacking will become handy with help of language syntax.<br />
Also, pattern matching syntax will be allowed in some places.<br />
<br />
=== Various places that you can use unpacking ===<br />
<br />
<ul><br />
<li style="margin-bottom: 1em;"><br />
Variable declaration<br />
<syntaxhighlight lang="d"><br />
auto {x, y} = {1, "hi"};<br />
{auto x, y} = {1, "hi"};<br />
{int x, string y} = {1, "hi"};<br />
assert(x == 1 && y == "hi");<br />
</syntaxhighlight><br />
<br />
<li style="margin-bottom: 1em;"><br />
Left side of assignment expression:<br />
<syntaxhighlight lang="d"><br />
auto tup = {1, "hi"};<br />
int a, string b;<br />
{a, b} = tup; // Rewritten as: a = tup[0], b = tup[1];<br />
{c, $} = tup; // Rewritten as: c = tup[0];<br />
</syntaxhighlight><br />
<br />
<strong>Note:</strong> Cannot swap values by tuple assignment.<br />
<syntaxhighlight lang="d"><br />
int x = 1, y = 2;<br />
{x, y} = {y, x};<br />
// Lowered to:<br />
// x = y, y = x;<br />
assert(y == 2);<br />
assert(x == 2);<br />
</syntaxhighlight><br />
<br />
<li style="margin-bottom: 1em;"><br />
Foreach iteratee<br />
<syntaxhighlight lang="d"><br />
foreach ({x, y}; zip([1,2,3], ["a","b","c"])) {}<br />
foreach (i, const {x, y}; [{1,2}, {3,4}, {5,6}, ...]) {<br />
// i == 0, 1, 2, ...<br />
// {x,y} == {1,2}, {3,4}, {5,6}, ...<br />
}<br />
</syntaxhighlight><br />
<br />
Index of array, key of associative array should not be<br />
included in the pattern. So<br />
<syntaxhighlight lang="d"><br />
foreach ({i, e}; arr) {} // only allowed when arr[n] is two-element tuple<br />
foreach ( i, e ; arr) {} // i captures implicitly given indices<br />
</syntaxhighlight><br />
This is necessary behavior for backward compatibility and disambiguation.<br />
<br />
And, this syntax (currently it is not enough documented)<br />
<syntaxhighlight lang="d"><br />
foreach (x, y; zip([1,2,3], ["a","b","c"])) {}<br />
</syntaxhighlight><br />
should be deprecated.<br />
<br />
If iterated range has ref front, pattern can have ref annotation.<br />
<syntaxhighlight lang="d"><br />
auto nums = [100, 200, 300];<br />
auto strs = ["a", "b", "c"];<br />
foreach (ref {x, y}; zip(nums, arr)) {<br />
x /= 10;<br />
y = x.to!string;<br />
}<br />
assert(nums == [ 10 , 20 , 30 ]);<br />
assert(strs == ["10", "20", "30"]);<br />
</syntaxhighlight><br />
<br />
<li style="margin-bottom: 1em;"><br />
Function parameters:<br />
<syntaxhighlight lang="d"><br />
void foo({int x, long y});<br />
void foo({int, string name}, string msg);<br />
// The first element of the tuple is 'unnamed'.<br />
<br />
// with lambdas:<br />
({A a, B b}) => a + b;<br />
({a, b}) => a + b;<br />
{a, b} => a + b;<br />
</syntaxhighlight><br />
<br />
</ul><br />
<br />
=== Various places that you can use unpacking and pattern matching ===<br />
<br />
<ul><br />
<li style="margin-bottom: 1em;"><br />
<code>if</code> statement with pattern matching<br />
<syntaxhighlight lang="d"><br />
if (auto {1, y} = tup) {<br />
// If the first element of tup (tup[0]) is equal to 1,<br />
// y captures the second element of tup (tup[1]).<br />
}<br />
</syntaxhighlight><br />
<br />
<li style="margin-bottom: 1em;"><br />
<code>case</code> values<br />
<syntaxhighlight lang="d"><br />
switch (tup) {<br />
case {1, 2}:<br />
case {$, 2}:<br />
case {1, x}: // capture tup[1] into 'x' when tup[0] == 1<br />
default: // same as {...}<br />
}<br />
</syntaxhighlight><br />
The cases with patterns will be evaluated in lexical order.<br />
<br />
</ul><br />
<br />
=== Difference between unpacking and pattern matching ===<br />
<br />
Pattern matching is only allowed in <code>if</code> and <code>case</code> statements.<br />
<syntaxhighlight lang="d"><br />
auto coord = {1, 2};<br />
if (auto {1, y} = coord) {} // if statement, ok<br />
switch(coord) { case {1, y}: ...; } // case statement, ok<br />
auto {1, y} = coord; // variable declaration, ng!<br />
</syntaxhighlight><br />
Because the two have conditional statements which is evaluated iff the pattern matches to the operand.<br />
Therefore <code>$identifier</code> is only allowed for the pattern match.<br />
<br />
<dl><br />
<dt><code>...</code> meaning for unpacking<br />
<dd><br />
<code>...</code> is used for the special unpacking placeholder. It matches zero or more elements.<br />
<syntaxhighlight lang="d"><br />
auto tup = {1, "hi", 3.14, [1,2,3]};<br />
if (auto {1, "hi", ...} = tup) {}<br />
</syntaxhighlight><br />
<br />
<dt><code>$</code> meaning for unpacking<br />
<dd><br />
<code>$</code> is used for the special unpacking placeholder for one element but not used. It does not conflict with curent <code>array.length</code> usage, because:<br />
<br />
<ol><br />
<li>all pattern matching is always appeared in statements.<br />
<li>To use statements in array indices, function literal is necessary. But:<br />
<syntaxhighlight lang="d"><br />
int[] a = [1,2,3];<br />
auto x = a[(){ return $-1; }()];<br />
// Error: cannnot use $ inside a function literal<br />
</syntaxhighlight><br />
</ol><br />
<br />
Therefore,<br />
<syntaxhighlight lang="d"><br />
auto x = a[(){<br />
if (auto {1, $} = tup) { // '$' is always *pattern placeholder*<br />
...<br />
}<br />
return 0;<br />
}];<br />
</syntaxhighlight><br />
<br />
<dt><code>$identifier</code> meaning for pattern matching<br />
<dd><br />
$identifier is used for the special syntax for pattern matching.<br />
Inside pattern, bare <code>identifier</code> will always make placeholder.<br />
<syntaxhighlight lang="d"><br />
if (auto {x, y} = coord) {<br />
// x and y captures coord's elements only in 'then' statement.<br />
}<br />
</syntaxhighlight><br />
<br />
If newly declared valiable conflicts with outer variables, it is refused.<br />
<syntaxhighlight lang="d"><br />
int x = 1;<br />
if (auto {x, y} = coord) { auto x2 = x; } // error, ambiguous 'x' usage<br />
</syntaxhighlight><br />
<br />
If you want to make a pattern with evaluating variable, use <code>$identifier</code>.<br />
<syntaxhighlight lang="d"><br />
int x = 1;<br />
if (auto {$x, y} = coord) { ... }<br />
// If the first element of coord is equal to 1 (== x), 'then' statement wil be evaluated.<br />
</syntaxhighlight><br />
<br />
</dl><br />
<br />
=== Unpacking and tuple expansion ===<br />
<br />
Unpacking implicitly requires tuple for its operand, so it can be automatically expanded.<br />
<syntaxhighlight lang="d"><br />
auto coord = {1, 2};<br />
if (auto {x, y} = coord) {}<br />
if (auto {x, y} = coord[]) {} // same, explicitly expands fields<br />
</syntaxhighlight><br />
<br />
=== Mismatching tuple element types and length ===<br />
<br />
<syntaxhighlight lang="d"><br />
auto tup = {1, "hi"}<br />
if (auto {num} = tup) {} // compile error<br />
if (auto {num, msg, x} = tup) {} // compile error<br />
if ({string num, int msg} = tup) {} // compile error<br />
<br />
if (auto {num, msg, ...} = tup) {} // ok, `...` matches to zero-elements.<br />
</syntaxhighlight><br />
<br />
<!--<br />
== TODO ==<br />
<br />
The things written in this section are not yet well defined, so they might be removed later.<br />
<br />
=== Tuple fields are always unnamed ===<br />
<br />
<syntaxhighlight lang="d"><br />
// The types of tuples which have field names<br />
alias MyPair = typeof({1, "hi"});<br />
alias MyRecord = typeof({count:1, msg:"hi"});<br />
static assert(is(MyPair == MyRecord)); // true or false?<br />
static assert(is(MyPair : MyRecord)); // true or false?<br />
static assert(is(MyRecord : MyPair)); // true or false?<br />
alias MyStudent = typeof({num:1, name:"John"});<br />
static assert(is(MyRecord == MyStudent)); // true or false?<br />
<br />
// named pattern is mostly useless<br />
if (auto {num:1, msg:"hi"} = pair) {}<br />
</syntaxhighlight><br />
<br />
=== Unpacking fields from object ===<br />
<br />
<syntaxhighlight lang="d"><br />
auto tup = {obj.a, obj.b, obj.c}<br />
is shorten to:<br />
auto tup = obj.{a, b, c}<br />
<br />
auto tup = {obj.a, obj.b.x, obj.b.y, obj.c}<br />
is shorten to:<br />
auto tup = obj.{a, b.{x, y}[], c}<br />
</syntaxhighlight><br />
<br />
* With `obj.{...}`, can guarantee that `obj` will be evaluated once.<br />
* The result of `obj.{...}` always makes a tuple.<br />
It is essential limitation that comes from the syntax .<br />
--><br />
<br />
== Use case of uniform tuple syntax ==<br />
<br />
Original D code:<br />
Source: http://forum.dlang.org/post/gridjorxqlpoytuxwpsg@forum.dlang.org<br />
<br />
<syntaxhighlight lang="d"><br />
import std.stdio, std.algorithm, std.typecons, std.container, std.array;<br />
<br />
auto encode(T)(Group!("a == b", T[]) sf) {<br />
auto heap = sf.map!(s => tuple(s[1], [tuple(s[0], "")]))<br />
.array.heapify!q{b < a};<br />
<br />
while (heap.length > 1) {<br />
auto lo = heap.front; heap.removeFront;<br />
auto hi = heap.front; heap.removeFront;<br />
foreach (ref pair; lo[1]) pair[1] = '0' ~ pair[1];<br />
foreach (ref pair; hi[1]) pair[1] = '1' ~ pair[1];<br />
heap.insert(tuple(lo[0] + hi[0], lo[1] ~ hi[1]));<br />
}<br />
return heap.front[1].schwartzSort!q{tuple(a[1].length, a[0])};<br />
}<br />
<br />
void main() {<br />
auto s = "this is an example for huffman encoding"d;<br />
foreach (p; s.dup.sort().release.group.encode)<br />
writefln("'%s' %s", p[]);<br />
}<br />
</syntaxhighlight><br />
<br />
<br />
This proposal:<br />
<br />
<syntaxhighlight lang="d"><br />
import std.stdio, std.algorithm, std.container, std.array;<br />
<br />
auto encode(T)(Group!("a == b", T[]) sf) {<br />
auto heap = sf.map!({c, f} => {f, [{c, ""}]}).array.heapify!q{b < a};<br />
<br />
while (heap.length > 1) {<br />
auto {lof, loa} = heap.front; heap.removeFront;<br />
auto {hif, hia} = heap.front; heap.removeFront;<br />
<br />
foreach ({$, ref e}; loa) e = '0' ~ e;<br />
foreach ({$, ref e}; hia) e = '1' ~ e;<br />
heap.insert({lof + hif, loa ~ hia});<br />
}<br />
<br />
return heap.front[1].schwartzSort!({c, e} => {e.length, c});<br />
}<br />
<br />
void main() {<br />
auto s = "this is an example for huffman encoding"d;<br />
foreach ({c, e}; s.dup.sort().release.group.encode)<br />
writefln("'%s' %s", c, e);<br />
}<br />
</syntaxhighlight><br />
<br />
<br />
Basic () syntax, perhaps the cleanest, but can't be used:<br />
<br />
<syntaxhighlight lang="d"><br />
import std.stdio, std.algorithm, std.container, std.array;<br />
<br />
auto encode(T)(Group!("a == b", T[]) sf) {<br />
auto heap = sf.map!((c, f) => (f, [(c, "")])).array.heapify!q{b < a};<br />
<br />
while (heap.length > 1) {<br />
auto (lof, loa) = heap.front; heap.removeFront;<br />
auto (hif, hia) = heap.front; heap.removeFront;<br />
foreach ((_, ref e); loa) e = '0' ~ e;<br />
foreach ((_, ref e); hia) e = '1' ~ e;<br />
heap.insert((lof + hif, loa ~ hia));<br />
}<br />
return heap.front[1].schwartzSort!((c, e) => (e.length, c));<br />
}<br />
<br />
void main() {<br />
auto s = "this is an example for huffman encoding"d;<br />
foreach ((c, e); s.dup.sort().release.group.encode)<br />
writefln("'%s' %s", c, e);<br />
}<br />
</syntaxhighlight><br />
<br />
<br />
tuple() syntax, clear, a bit long:<br />
<br />
<syntaxhighlight lang="d"><br />
import std.stdio, std.algorithm, std.container, std.array;<br />
<br />
auto encode(T)(Group!("a == b", T[]) sf) {<br />
auto heap = sf.map!(tuple(c, f) => tuple(f, [tuple(c, "")]))<br />
.array.heapify!q{b < a};<br />
<br />
while (heap.length > 1) {<br />
auto tuple(lof, loa) = heap.front; heap.removeFront;<br />
auto tuple(hif, hia) = heap.front; heap.removeFront;<br />
foreach (tuple(_, ref e); loa) e = '0' ~ e;<br />
foreach (tuple(_, ref e); hia) e = '1' ~ e;<br />
heap.insert(tuple(lof + hif, loa ~ hia));<br />
}<br />
return heap.front[1].schwartzSort!(tuple(c, e) => tuple(e.length, c));<br />
}<br />
<br />
void main() {<br />
auto s = "this is an example for huffman encoding"d;<br />
foreach (tuple(c, e); s.dup.sort().release.group.encode)<br />
writefln("'%s' %s", c, e);<br />
}<br />
</syntaxhighlight><br />
<br />
<br />
@{} syntax, noisy:<br />
<br />
<syntaxhighlight lang="d"><br />
import std.stdio, std.algorithm, std.container, std.array;<br />
<br />
auto encode(T)(Group!("a == b", T[]) sf) {<br />
auto heap = sf.map!(@{c, f} => {f, [@{c, ""}]}).array.heapify!q{b < a};<br />
<br />
while (heap.length > 1) {<br />
auto @{lof, loa} = heap.front; heap.removeFront;<br />
auto @{hif, hia} = heap.front; heap.removeFront;<br />
foreach (@{_, ref e}; loa) e = '0' ~ e;<br />
foreach (@{_, ref e}; hia) e = '1' ~ e;<br />
heap.insert(@{lof + hif, loa ~ hia});<br />
}<br />
return heap.front[1].schwartzSort!(@{c, e} => @{e.length, c});<br />
}<br />
<br />
void main() {<br />
auto s = "this is an example for huffman encoding"d;<br />
foreach (@{c, e}; s.dup.sort().release.group.encode)<br />
writefln("'%s' %s", c, e);<br />
}<br />
</syntaxhighlight><br />
<br />
<br />
<br />
(||) banana syntax, a bit confusing, but IDEs can visualize (| and |) as some nice Unicode glyps:<br />
<br />
<syntaxhighlight lang="d"><br />
import std.stdio, std.algorithm, std.container, std.array;<br />
<br />
auto encode(T)(Group!("a == b", T[]) sf) {<br />
auto heap = sf.map!((|c, f|) => (|f, [(|c, ""|)]|)).array.heapify!q{b < a};<br />
<br />
while (heap.length > 1) {<br />
auto (|lof, loa|) = heap.front; heap.removeFront;<br />
auto (|hif, hia|) = heap.front; heap.removeFront;<br />
foreach ((|_, ref e|); loa) e = '0' ~ e;<br />
foreach ((|_, ref e|); hia) e = '1' ~ e;<br />
heap.insert((|lof + hif, loa ~ hia|));<br />
}<br />
return heap.front[1].schwartzSort!((|c, e|) => (|e.length, c|));<br />
}<br />
<br />
void main() {<br />
auto s = "this is an example for huffman encoding"d;<br />
foreach ((|c, e|); s.dup.sort().release.group.encode)<br />
writefln("'%s' %s", c, e);<br />
}<br />
</syntaxhighlight><br />
<br />
&#2985;&#2986;<br />
&#ba9;&#baa;<br />
<br />
<br />
t{} syntax, the t is not very easy to see, but it's short and it's similar to the q{} for token strings:<br />
<br />
<syntaxhighlight lang="d"><br />
import std.stdio, std.algorithm, std.container, std.array;<br />
<br />
auto encode(T)(Group!("a == b", T[]) sf) {<br />
auto heap = sf.map!(t{c, f} => {f, [t{c, ""}]}).array.heapify!q{b < a};<br />
<br />
while (heap.length > 1) {<br />
auto t{lof, loa} = heap.front; heap.removeFront;<br />
auto t{hif, hia} = heap.front; heap.removeFront;<br />
foreach (t{_, ref e}; loa) e = '0' ~ e;<br />
foreach (t{_, ref e}; hia) e = '1' ~ e;<br />
heap.insert(t{lof + hif, loa ~ hia});<br />
}<br />
return heap.front[1].schwartzSort!(t{c, e} => t{e.length, c});<br />
}<br />
<br />
void main() {<br />
auto s = "this is an example for huffman encoding"d;<br />
foreach (t{c, e}; s.dup.sort().release.group.encode)<br />
writefln("'%s' %s", c, e);<br />
}<br />
</syntaxhighlight><br />
<br />
<br />
<code>#()</code> syntax (suggested by Meta), short, not too much noisy, and it's visually searchable and popping more than t{}:<br />
<br />
<syntaxhighlight lang="d"><br />
import std.stdio, std.algorithm, std.container, std.array;<br />
<br />
auto encode(T)(Group!("a == b", T[]) sf) {<br />
auto heap = sf.map!(#(c, f) => #(f, [#(c, "")])).array.heapify!q{b < a};<br />
<br />
while (heap.length > 1) {<br />
auto #(lof, loa) = heap.front; heap.removeFront;<br />
auto #(hif, hia) = heap.front; heap.removeFront;<br />
foreach (#(_, ref e); loa) e = '0' ~ e;<br />
foreach (#(_, ref e); hia) e = '1' ~ e;<br />
heap.insert(#(lof + hif, loa ~ hia));<br />
}<br />
return heap.front[1].schwartzSort!(#(c, e) => #(e.length, c));<br />
}<br />
<br />
void main() {<br />
auto s = "this is an example for huffman encoding"d;<br />
foreach (#(c, e); s.dup.sort().release.group.encode)<br />
writefln("'%s' %s", c, e);<br />
}<br />
</syntaxhighlight><br />
<br />
== Copyright ==<br />
<br />
This document has been placed in the Public Domain.</div>
Bearophile
https://wiki.dlang.org/?title=DIP32&diff=2868
DIP32
2013-08-16T23:39:10Z
<p>Bearophile: One more possible syntax added</p>
<hr />
<div>== DIP32: Uniform tuple syntax ==<br />
<br />
{| class="wikitable"<br />
!Title: <br />
!'''Uniform tuple syntax'''<br />
|-<br />
|DIP:<br />
|32<br />
|-<br />
|Version:<br />
|1<br />
|-<br />
|Status:<br />
|Draft<br />
|-<br />
|Created:<br />
|2013-03-29<br />
|-<br />
|Last Modified:<br />
|2013-03-29<br />
|-<br />
|Author:<br />
|Hara Kenji<br />
|-<br />
|Links:<br />
|<br />
|}<br />
<br />
== Abstract ==<br />
<br />
This is a proposal for consistent tuple syntax and features.<br />
<br />
== Generic type/expression tuple syntax ==<br />
<br />
Use braces and commas.<br />
Inside tuple literal, <code>;</code> never appears. So it will not be confused with lambdas and ScopeStatements.<br />
<br />
<syntaxhighlight lang="d"><br />
auto tup = {10, "hi", 3.14};<br />
assert(tup[0] == 10); // indexing access<br />
<br />
// In initializers<br />
auto fp = {;}; // lambda<br />
auto dg = {x;}; // lambda<br />
auto tup = {}; // zero-element tuple (Syntax meaning will be changed!)<br />
Struct s = {}; // StructInitializer<br />
<br />
// In function arguments<br />
foo({;}); // lambda<br />
foo({}); // zero-element tuple (Syntax meaning will be changed!)<br />
foo({1}); // one-element tuple<br />
foo({1, "hi"}); // two-element tuple<br />
<br />
// In statements<br />
void test() {<br />
{1, "hi"} // two-element tuple<br />
{1} // one-element tuple<br />
{} // ScopeStatement with no statements, not zero-element tuple.<br />
// {} = tup; // no-side effect assignment.<br />
// {} = tup; // meaningless unpacking & declaration.<br />
// if (true) {} func;<br />
// ScopeStatement and parenthesis-less func call.<br />
}<br />
<br />
// declare tuple value by using explicit tuple type<br />
{int, string} tup = {1, "hi"};<br />
assert(tup[0] == 1);<br />
assert(tup[1] == "hi");<br />
static assert(is(typeof(tup) == {int, string})); // tuple type<br />
<br />
alias TL = {int, string[], double[string]}; // types<br />
alias Fields = {int, "num", int[string], "map"}; // mixing<br />
alias date = {2013, 3, 29}; // values<br />
<br />
foreach (Float; {float, double, real}) { ... }<br />
</syntaxhighlight><br />
<br />
<!--<br />
{int, int, int} d = date; // works, but...<br />
void getDate({int y, int m, int d}) { ... }<br />
getDate( date ); // doesn't work...?<br />
getDate({date}); // works.<br />
--><br />
<br />
== Tuple unpacking and pattern matching ==<br />
<br />
Tuple value unpacking will become handy with help of language syntax.<br />
Also, pattern matching syntax will be allowed in some places.<br />
<br />
=== Various places that you can use unpacking ===<br />
<br />
<ul><br />
<li style="margin-bottom: 1em;"><br />
Variable declaration<br />
<syntaxhighlight lang="d"><br />
auto {x, y} = {1, "hi"};<br />
{auto x, y} = {1, "hi"};<br />
{int x, string y} = {1, "hi"};<br />
assert(x == 1 && y == "hi");<br />
</syntaxhighlight><br />
<br />
<li style="margin-bottom: 1em;"><br />
Left side of assignment expression:<br />
<syntaxhighlight lang="d"><br />
auto tup = {1, "hi"};<br />
int a, string b;<br />
{a, b} = tup; // Rewritten as: a = tup[0], b = tup[1];<br />
{c, $} = tup; // Rewritten as: c = tup[0];<br />
</syntaxhighlight><br />
<br />
<strong>Note:</strong> Cannot swap values by tuple assignment.<br />
<syntaxhighlight lang="d"><br />
int x = 1, y = 2;<br />
{x, y} = {y, x};<br />
// Lowered to:<br />
// x = y, y = x;<br />
assert(y == 2);<br />
assert(x == 2);<br />
</syntaxhighlight><br />
<br />
<li style="margin-bottom: 1em;"><br />
Foreach iteratee<br />
<syntaxhighlight lang="d"><br />
foreach ({x, y}; zip([1,2,3], ["a","b","c"])) {}<br />
foreach (i, const {x, y}; [{1,2}, {3,4}, {5,6}, ...]) {<br />
// i == 0, 1, 2, ...<br />
// {x,y} == {1,2}, {3,4}, {5,6}, ...<br />
}<br />
</syntaxhighlight><br />
<br />
Index of array, key of associative array should not be<br />
included in the pattern. So<br />
<syntaxhighlight lang="d"><br />
foreach ({i, e}; arr) {} // only allowed when arr[n] is two-element tuple<br />
foreach ( i, e ; arr) {} // i captures implicitly given indices<br />
</syntaxhighlight><br />
This is necessary behavior for backward compatibility and disambiguation.<br />
<br />
And, this syntax (currently it is not enough documented)<br />
<syntaxhighlight lang="d"><br />
foreach (x, y; zip([1,2,3], ["a","b","c"])) {}<br />
</syntaxhighlight><br />
should be deprecated.<br />
<br />
If iterated range has ref front, pattern can have ref annotation.<br />
<syntaxhighlight lang="d"><br />
auto nums = [100, 200, 300];<br />
auto strs = ["a", "b", "c"];<br />
foreach (ref {x, y}; zip(nums, arr)) {<br />
x /= 10;<br />
y = x.to!string;<br />
}<br />
assert(nums == [ 10 , 20 , 30 ]);<br />
assert(strs == ["10", "20", "30"]);<br />
</syntaxhighlight><br />
<br />
<li style="margin-bottom: 1em;"><br />
Function parameters:<br />
<syntaxhighlight lang="d"><br />
void foo({int x, long y});<br />
void foo({int, string name}, string msg);<br />
// The first element of the tuple is 'unnamed'.<br />
<br />
// with lambdas:<br />
({A a, B b}) => a + b;<br />
({a, b}) => a + b;<br />
{a, b} => a + b;<br />
</syntaxhighlight><br />
<br />
</ul><br />
<br />
=== Various places that you can use unpacking and pattern matching ===<br />
<br />
<ul><br />
<li style="margin-bottom: 1em;"><br />
<code>if</code> statement with pattern matching<br />
<syntaxhighlight lang="d"><br />
if (auto {1, y} = tup) {<br />
// If the first element of tup (tup[0]) is equal to 1,<br />
// y captures the second element of tup (tup[1]).<br />
}<br />
</syntaxhighlight><br />
<br />
<li style="margin-bottom: 1em;"><br />
<code>case</code> values<br />
<syntaxhighlight lang="d"><br />
switch (tup) {<br />
case {1, 2}:<br />
case {$, 2}:<br />
case {1, x}: // capture tup[1] into 'x' when tup[0] == 1<br />
default: // same as {...}<br />
}<br />
</syntaxhighlight><br />
The cases with patterns will be evaluated in lexical order.<br />
<br />
</ul><br />
<br />
=== Difference between unpacking and pattern matching ===<br />
<br />
Pattern matching is only allowed in <code>if</code> and <code>case</code> statements.<br />
<syntaxhighlight lang="d"><br />
auto coord = {1, 2};<br />
if (auto {1, y} = coord) {} // if statement, ok<br />
switch(coord) { case {1, y}: ...; } // case statement, ok<br />
auto {1, y} = coord; // variable declaration, ng!<br />
</syntaxhighlight><br />
Because the two have conditional statements which is evaluated iff the pattern matches to the operand.<br />
Therefore <code>$identifier</code> is only allowed for the pattern match.<br />
<br />
<dl><br />
<dt><code>...</code> meaning for unpacking<br />
<dd><br />
<code>...</code> is used for the special unpacking placeholder. It matches zero or more elements.<br />
<syntaxhighlight lang="d"><br />
auto tup = {1, "hi", 3.14, [1,2,3]};<br />
if (auto {1, "hi", ...} = tup) {}<br />
</syntaxhighlight><br />
<br />
<dt><code>$</code> meaning for unpacking<br />
<dd><br />
<code>$</code> is used for the special unpacking placeholder for one element but not used. It does not conflict with curent <code>array.length</code> usage, because:<br />
<br />
<ol><br />
<li>all pattern matching is always appeared in statements.<br />
<li>To use statements in array indices, function literal is necessary. But:<br />
<syntaxhighlight lang="d"><br />
int[] a = [1,2,3];<br />
auto x = a[(){ return $-1; }()];<br />
// Error: cannnot use $ inside a function literal<br />
</syntaxhighlight><br />
</ol><br />
<br />
Therefore,<br />
<syntaxhighlight lang="d"><br />
auto x = a[(){<br />
if (auto {1, $} = tup) { // '$' is always *pattern placeholder*<br />
...<br />
}<br />
return 0;<br />
}];<br />
</syntaxhighlight><br />
<br />
<dt><code>$identifier</code> meaning for pattern matching<br />
<dd><br />
$identifier is used for the special syntax for pattern matching.<br />
Inside pattern, bare <code>identifier</code> will always make placeholder.<br />
<syntaxhighlight lang="d"><br />
if (auto {x, y} = coord) {<br />
// x and y captures coord's elements only in 'then' statement.<br />
}<br />
</syntaxhighlight><br />
<br />
If newly declared valiable conflicts with outer variables, it is refused.<br />
<syntaxhighlight lang="d"><br />
int x = 1;<br />
if (auto {x, y} = coord) { auto x2 = x; } // error, ambiguous 'x' usage<br />
</syntaxhighlight><br />
<br />
If you want to make a pattern with evaluating variable, use <code>$identifier</code>.<br />
<syntaxhighlight lang="d"><br />
int x = 1;<br />
if (auto {$x, y} = coord) { ... }<br />
// If the first element of coord is equal to 1 (== x), 'then' statement wil be evaluated.<br />
</syntaxhighlight><br />
<br />
</dl><br />
<br />
=== Unpacking and tuple expansion ===<br />
<br />
Unpacking implicitly requires tuple for its operand, so it can be automatically expanded.<br />
<syntaxhighlight lang="d"><br />
auto coord = {1, 2};<br />
if (auto {x, y} = coord) {}<br />
if (auto {x, y} = coord[]) {} // same, explicitly expands fields<br />
</syntaxhighlight><br />
<br />
=== Mismatching tuple element types and length ===<br />
<br />
<syntaxhighlight lang="d"><br />
auto tup = {1, "hi"}<br />
if (auto {num} = tup) {} // compile error<br />
if (auto {num, msg, x} = tup) {} // compile error<br />
if ({string num, int msg} = tup) {} // compile error<br />
<br />
if (auto {num, msg, ...} = tup) {} // ok, `...` matches to zero-elements.<br />
</syntaxhighlight><br />
<br />
<!--<br />
== TODO ==<br />
<br />
The things written in this section are not yet well defined, so they might be removed later.<br />
<br />
=== Tuple fields are always unnamed ===<br />
<br />
<syntaxhighlight lang="d"><br />
// The types of tuples which have field names<br />
alias MyPair = typeof({1, "hi"});<br />
alias MyRecord = typeof({count:1, msg:"hi"});<br />
static assert(is(MyPair == MyRecord)); // true or false?<br />
static assert(is(MyPair : MyRecord)); // true or false?<br />
static assert(is(MyRecord : MyPair)); // true or false?<br />
alias MyStudent = typeof({num:1, name:"John"});<br />
static assert(is(MyRecord == MyStudent)); // true or false?<br />
<br />
// named pattern is mostly useless<br />
if (auto {num:1, msg:"hi"} = pair) {}<br />
</syntaxhighlight><br />
<br />
=== Unpacking fields from object ===<br />
<br />
<syntaxhighlight lang="d"><br />
auto tup = {obj.a, obj.b, obj.c}<br />
is shorten to:<br />
auto tup = obj.{a, b, c}<br />
<br />
auto tup = {obj.a, obj.b.x, obj.b.y, obj.c}<br />
is shorten to:<br />
auto tup = obj.{a, b.{x, y}[], c}<br />
</syntaxhighlight><br />
<br />
* With `obj.{...}`, can guarantee that `obj` will be evaluated once.<br />
* The result of `obj.{...}` always makes a tuple.<br />
It is essential limitation that comes from the syntax .<br />
--><br />
<br />
== Use case of uniform tuple syntax ==<br />
<br />
Original D code:<br />
Source: http://forum.dlang.org/post/gridjorxqlpoytuxwpsg@forum.dlang.org<br />
<br />
<syntaxhighlight lang="d"><br />
import std.stdio, std.algorithm, std.typecons, std.container, std.array;<br />
<br />
auto encode(T)(Group!("a == b", T[]) sf) {<br />
auto heap = sf.map!(s => tuple(s[1], [tuple(s[0], "")]))<br />
.array.heapify!q{b < a};<br />
<br />
while (heap.length > 1) {<br />
auto lo = heap.front; heap.removeFront;<br />
auto hi = heap.front; heap.removeFront;<br />
foreach (ref pair; lo[1]) pair[1] = '0' ~ pair[1];<br />
foreach (ref pair; hi[1]) pair[1] = '1' ~ pair[1];<br />
heap.insert(tuple(lo[0] + hi[0], lo[1] ~ hi[1]));<br />
}<br />
return heap.front[1].schwartzSort!q{tuple(a[1].length, a[0])};<br />
}<br />
<br />
void main() {<br />
auto s = "this is an example for huffman encoding"d;<br />
foreach (p; s.dup.sort().release.group.encode)<br />
writefln("'%s' %s", p[]);<br />
}<br />
</syntaxhighlight><br />
<br />
<br />
This proposal:<br />
<br />
<syntaxhighlight lang="d"><br />
import std.stdio, std.algorithm, std.container, std.array;<br />
<br />
auto encode(T)(Group!("a == b", T[]) sf) {<br />
auto heap = sf.map!({c, f} => {f, [{c, ""}]}).array.heapify!q{b < a};<br />
<br />
while (heap.length > 1) {<br />
auto {lof, loa} = heap.front; heap.removeFront;<br />
auto {hif, hia} = heap.front; heap.removeFront;<br />
<br />
foreach ({$, ref e}; loa) e = '0' ~ e;<br />
foreach ({$, ref e}; hia) e = '1' ~ e;<br />
heap.insert({lof + hif, loa ~ hia});<br />
}<br />
<br />
return heap.front[1].schwartzSort!({c, e} => {e.length, c});<br />
}<br />
<br />
void main() {<br />
auto s = "this is an example for huffman encoding"d;<br />
foreach ({c, e}; s.dup.sort().release.group.encode)<br />
writefln("'%s' %s", c, e);<br />
}<br />
</syntaxhighlight><br />
<br />
<br />
Basic () syntax, perhaps the cleanest, but can't be used:<br />
<br />
<syntaxhighlight lang="d"><br />
import std.stdio, std.algorithm, std.container, std.array;<br />
<br />
auto encode(T)(Group!("a == b", T[]) sf) {<br />
auto heap = sf.map!((c, f) => (f, [(c, "")])).array.heapify!q{b < a};<br />
<br />
while (heap.length > 1) {<br />
auto (lof, loa) = heap.front; heap.removeFront;<br />
auto (hif, hia) = heap.front; heap.removeFront;<br />
foreach ((_, ref e); loa) e = '0' ~ e;<br />
foreach ((_, ref e); hia) e = '1' ~ e;<br />
heap.insert((lof + hif, loa ~ hia));<br />
}<br />
return heap.front[1].schwartzSort!((c, e) => (e.length, c));<br />
}<br />
<br />
void main() {<br />
auto s = "this is an example for huffman encoding"d;<br />
foreach ((c, e); s.dup.sort().release.group.encode)<br />
writefln("'%s' %s", c, e);<br />
}<br />
</syntaxhighlight><br />
<br />
<br />
tuple() syntax, clear, a bit long:<br />
<br />
<syntaxhighlight lang="d"><br />
import std.stdio, std.algorithm, std.container, std.array;<br />
<br />
auto encode(T)(Group!("a == b", T[]) sf) {<br />
auto heap = sf.map!(tuple(c, f) => tuple(f, [tuple(c, "")]))<br />
.array.heapify!q{b < a};<br />
<br />
while (heap.length > 1) {<br />
auto tuple(lof, loa) = heap.front; heap.removeFront;<br />
auto tuple(hif, hia) = heap.front; heap.removeFront;<br />
foreach (tuple(_, ref e); loa) e = '0' ~ e;<br />
foreach (tuple(_, ref e); hia) e = '1' ~ e;<br />
heap.insert(tuple(lof + hif, loa ~ hia));<br />
}<br />
return heap.front[1].schwartzSort!(tuple(c, e) => tuple(e.length, c));<br />
}<br />
<br />
void main() {<br />
auto s = "this is an example for huffman encoding"d;<br />
foreach (tuple(c, e); s.dup.sort().release.group.encode)<br />
writefln("'%s' %s", c, e);<br />
}<br />
</syntaxhighlight><br />
<br />
<br />
@{} syntax, noisy:<br />
<br />
<syntaxhighlight lang="d"><br />
import std.stdio, std.algorithm, std.container, std.array;<br />
<br />
auto encode(T)(Group!("a == b", T[]) sf) {<br />
auto heap = sf.map!(@{c, f} => {f, [@{c, ""}]}).array.heapify!q{b < a};<br />
<br />
while (heap.length > 1) {<br />
auto @{lof, loa} = heap.front; heap.removeFront;<br />
auto @{hif, hia} = heap.front; heap.removeFront;<br />
foreach (@{_, ref e}; loa) e = '0' ~ e;<br />
foreach (@{_, ref e}; hia) e = '1' ~ e;<br />
heap.insert(@{lof + hif, loa ~ hia});<br />
}<br />
return heap.front[1].schwartzSort!(@{c, e} => @{e.length, c});<br />
}<br />
<br />
void main() {<br />
auto s = "this is an example for huffman encoding"d;<br />
foreach (@{c, e}; s.dup.sort().release.group.encode)<br />
writefln("'%s' %s", c, e);<br />
}<br />
</syntaxhighlight><br />
<br />
<br />
<br />
(||) banana syntax, a bit confusing, but IDEs can visualize (| and |) as some nice Unicode glyps:<br />
<br />
<syntaxhighlight lang="d"><br />
import std.stdio, std.algorithm, std.container, std.array;<br />
<br />
auto encode(T)(Group!("a == b", T[]) sf) {<br />
auto heap = sf.map!((|c, f|) => (|f, [(|c, ""|)]|)).array.heapify!q{b < a};<br />
<br />
while (heap.length > 1) {<br />
auto (|lof, loa|) = heap.front; heap.removeFront;<br />
auto (|hif, hia|) = heap.front; heap.removeFront;<br />
foreach ((|_, ref e|); loa) e = '0' ~ e;<br />
foreach ((|_, ref e|); hia) e = '1' ~ e;<br />
heap.insert((|lof + hif, loa ~ hia|));<br />
}<br />
return heap.front[1].schwartzSort!((|c, e|) => (|e.length, c|));<br />
}<br />
<br />
void main() {<br />
auto s = "this is an example for huffman encoding"d;<br />
foreach ((|c, e|); s.dup.sort().release.group.encode)<br />
writefln("'%s' %s", c, e);<br />
}<br />
</syntaxhighlight><br />
<br />
<br />
t{} syntax, the t is not very easy to see, but it's short and it's similar to the q{} for token strings:<br />
<br />
<syntaxhighlight lang="d"><br />
import std.stdio, std.algorithm, std.container, std.array;<br />
<br />
auto encode(T)(Group!("a == b", T[]) sf) {<br />
auto heap = sf.map!(t{c, f} => {f, [t{c, ""}]}).array.heapify!q{b < a};<br />
<br />
while (heap.length > 1) {<br />
auto t{lof, loa} = heap.front; heap.removeFront;<br />
auto t{hif, hia} = heap.front; heap.removeFront;<br />
foreach (t{_, ref e}; loa) e = '0' ~ e;<br />
foreach (t{_, ref e}; hia) e = '1' ~ e;<br />
heap.insert(t{lof + hif, loa ~ hia});<br />
}<br />
return heap.front[1].schwartzSort!(t{c, e} => t{e.length, c});<br />
}<br />
<br />
void main() {<br />
auto s = "this is an example for huffman encoding"d;<br />
foreach (t{c, e}; s.dup.sort().release.group.encode)<br />
writefln("'%s' %s", c, e);<br />
}<br />
</syntaxhighlight><br />
<br />
<br />
<code>#()</code> syntax (suggested by Meta), short, not too much noisy, and it's visually searchable and popping more than t{}:<br />
<br />
<syntaxhighlight lang="d"><br />
import std.stdio, std.algorithm, std.container, std.array;<br />
<br />
auto encode(T)(Group!("a == b", T[]) sf) {<br />
auto heap = sf.map!(#(c, f) => #(f, [#(c, "")])).array.heapify!q{b < a};<br />
<br />
while (heap.length > 1) {<br />
auto #(lof, loa) = heap.front; heap.removeFront;<br />
auto #(hif, hia) = heap.front; heap.removeFront;<br />
foreach (#(_, ref e); loa) e = '0' ~ e;<br />
foreach (#(_, ref e); hia) e = '1' ~ e;<br />
heap.insert(#(lof + hif, loa ~ hia));<br />
}<br />
return heap.front[1].schwartzSort!(#(c, e) => #(e.length, c));<br />
}<br />
<br />
void main() {<br />
auto s = "this is an example for huffman encoding"d;<br />
foreach (#(c, e); s.dup.sort().release.group.encode)<br />
writefln("'%s' %s", c, e);<br />
}<br />
</syntaxhighlight><br />
<br />
== Copyright ==<br />
<br />
This document has been placed in the Public Domain.</div>
Bearophile
https://wiki.dlang.org/?title=DIP32&diff=2866
DIP32
2013-08-12T21:31:29Z
<p>Bearophile: Updated section 'Use case of uniform tuple syntax'</p>
<hr />
<div>== DIP32: Uniform tuple syntax ==<br />
<br />
{| class="wikitable"<br />
!Title: <br />
!'''Uniform tuple syntax'''<br />
|-<br />
|DIP:<br />
|32<br />
|-<br />
|Version:<br />
|1<br />
|-<br />
|Status:<br />
|Draft<br />
|-<br />
|Created:<br />
|2013-03-29<br />
|-<br />
|Last Modified:<br />
|2013-03-29<br />
|-<br />
|Author:<br />
|Hara Kenji<br />
|-<br />
|Links:<br />
|<br />
|}<br />
<br />
== Abstract ==<br />
<br />
This is a proposal for consistent tuple syntax and features.<br />
<br />
== Generic type/expression tuple syntax ==<br />
<br />
Use braces and commas.<br />
Inside tuple literal, <code>;</code> never appears. So it will not be confused with lambdas and ScopeStatements.<br />
<br />
<syntaxhighlight lang="d"><br />
auto tup = {10, "hi", 3.14};<br />
assert(tup[0] == 10); // indexing access<br />
<br />
// In initializers<br />
auto fp = {;}; // lambda<br />
auto dg = {x;}; // lambda<br />
auto tup = {}; // zero-element tuple (Syntax meaning will be changed!)<br />
Struct s = {}; // StructInitializer<br />
<br />
// In function arguments<br />
foo({;}); // lambda<br />
foo({}); // zero-element tuple (Syntax meaning will be changed!)<br />
foo({1}); // one-element tuple<br />
foo({1, "hi"}); // two-element tuple<br />
<br />
// In statements<br />
void test() {<br />
{1, "hi"} // two-element tuple<br />
{1} // one-element tuple<br />
{} // ScopeStatement with no statements, not zero-element tuple.<br />
// {} = tup; // no-side effect assignment.<br />
// {} = tup; // meaningless unpacking & declaration.<br />
// if (true) {} func;<br />
// ScopeStatement and parenthesis-less func call.<br />
}<br />
<br />
// declare tuple value by using explicit tuple type<br />
{int, string} tup = {1, "hi"};<br />
assert(tup[0] == 1);<br />
assert(tup[1] == "hi");<br />
static assert(is(typeof(tup) == {int, string})); // tuple type<br />
<br />
alias TL = {int, string[], double[string]}; // types<br />
alias Fields = {int, "num", int[string], "map"}; // mixing<br />
alias date = {2013, 3, 29}; // values<br />
<br />
foreach (Float; {float, double, real}) { ... }<br />
</syntaxhighlight><br />
<br />
<!--<br />
{int, int, int} d = date; // works, but...<br />
void getDate({int y, int m, int d}) { ... }<br />
getDate( date ); // doesn't work...?<br />
getDate({date}); // works.<br />
--><br />
<br />
== Tuple unpacking and pattern matching ==<br />
<br />
Tuple value unpacking will become handy with help of language syntax.<br />
Also, pattern matching syntax will be allowed in some places.<br />
<br />
=== Various places that you can use unpacking ===<br />
<br />
<ul><br />
<li style="margin-bottom: 1em;"><br />
Variable declaration<br />
<syntaxhighlight lang="d"><br />
auto {x, y} = {1, "hi"};<br />
{auto x, y} = {1, "hi"};<br />
{int x, string y} = {1, "hi"};<br />
assert(x == 1 && y == "hi");<br />
</syntaxhighlight><br />
<br />
<li style="margin-bottom: 1em;"><br />
Left side of assignment expression:<br />
<syntaxhighlight lang="d"><br />
auto tup = {1, "hi"};<br />
int a, string b;<br />
{a, b} = tup; // Rewritten as: a = tup[0], b = tup[1];<br />
{c, $} = tup; // Rewritten as: c = tup[0];<br />
</syntaxhighlight><br />
<br />
<strong>Note:</strong> Cannot swap values by tuple assignment.<br />
<syntaxhighlight lang="d"><br />
int x = 1, y = 2;<br />
{x, y} = {y, x};<br />
// Lowered to:<br />
// x = y, y = x;<br />
assert(y == 2);<br />
assert(x == 2);<br />
</syntaxhighlight><br />
<br />
<li style="margin-bottom: 1em;"><br />
Foreach iteratee<br />
<syntaxhighlight lang="d"><br />
foreach ({x, y}; zip([1,2,3], ["a","b","c"])) {}<br />
foreach (i, const {x, y}; [{1,2}, {3,4}, {5,6}, ...]) {<br />
// i == 0, 1, 2, ...<br />
// {x,y} == {1,2}, {3,4}, {5,6}, ...<br />
}<br />
</syntaxhighlight><br />
<br />
Index of array, key of associative array should not be<br />
included in the pattern. So<br />
<syntaxhighlight lang="d"><br />
foreach ({i, e}; arr) {} // only allowed when arr[n] is two-element tuple<br />
foreach ( i, e ; arr) {} // i captures implicitly given indices<br />
</syntaxhighlight><br />
This is necessary behavior for backward compatibility and disambiguation.<br />
<br />
And, this syntax (currently it is not enough documented)<br />
<syntaxhighlight lang="d"><br />
foreach (x, y; zip([1,2,3], ["a","b","c"])) {}<br />
</syntaxhighlight><br />
should be deprecated.<br />
<br />
If iterated range has ref front, pattern can have ref annotation.<br />
<syntaxhighlight lang="d"><br />
auto nums = [100, 200, 300];<br />
auto strs = ["a", "b", "c"];<br />
foreach (ref {x, y}; zip(nums, arr)) {<br />
x /= 10;<br />
y = x.to!string;<br />
}<br />
assert(nums == [ 10 , 20 , 30 ]);<br />
assert(strs == ["10", "20", "30"]);<br />
</syntaxhighlight><br />
<br />
<li style="margin-bottom: 1em;"><br />
Function parameters:<br />
<syntaxhighlight lang="d"><br />
void foo({int x, long y});<br />
void foo({int, string name}, string msg);<br />
// The first element of the tuple is 'unnamed'.<br />
<br />
// with lambdas:<br />
({A a, B b}) => a + b;<br />
({a, b}) => a + b;<br />
{a, b} => a + b;<br />
</syntaxhighlight><br />
<br />
</ul><br />
<br />
=== Various places that you can use unpacking and pattern matching ===<br />
<br />
<ul><br />
<li style="margin-bottom: 1em;"><br />
<code>if</code> statement with pattern matching<br />
<syntaxhighlight lang="d"><br />
if (auto {1, y} = tup) {<br />
// If the first element of tup (tup[0]) is equal to 1,<br />
// y captures the second element of tup (tup[1]).<br />
}<br />
</syntaxhighlight><br />
<br />
<li style="margin-bottom: 1em;"><br />
<code>case</code> values<br />
<syntaxhighlight lang="d"><br />
switch (tup) {<br />
case {1, 2}:<br />
case {$, 2}:<br />
case {1, x}: // capture tup[1] into 'x' when tup[0] == 1<br />
default: // same as {...}<br />
}<br />
</syntaxhighlight><br />
The cases with patterns will be evaluated in lexical order.<br />
<br />
</ul><br />
<br />
=== Difference between unpacking and pattern matching ===<br />
<br />
Pattern matching is only allowed in <code>if</code> and <code>case</code> statements.<br />
<syntaxhighlight lang="d"><br />
auto coord = {1, 2};<br />
if (auto {1, y} = coord) {} // if statement, ok<br />
switch(coord) { case {1, y}: ...; } // case statement, ok<br />
auto {1, y} = coord; // variable declaration, ng!<br />
</syntaxhighlight><br />
Because the two have conditional statements which is evaluated iff the pattern matches to the operand.<br />
Therefore <code>$identifier</code> is only allowed for the pattern match.<br />
<br />
<dl><br />
<dt><code>...</code> meaning for unpacking<br />
<dd><br />
<code>...</code> is used for the special unpacking placeholder. It matches zero or more elements.<br />
<syntaxhighlight lang="d"><br />
auto tup = {1, "hi", 3.14, [1,2,3]};<br />
if (auto {1, "hi", ...} = tup) {}<br />
</syntaxhighlight><br />
<br />
<dt><code>$</code> meaning for unpacking<br />
<dd><br />
<code>$</code> is used for the special unpacking placeholder for one element but not used. It does not conflict with curent <code>array.length</code> usage, because:<br />
<br />
<ol><br />
<li>all pattern matching is always appeared in statements.<br />
<li>To use statements in array indices, function literal is necessary. But:<br />
<syntaxhighlight lang="d"><br />
int[] a = [1,2,3];<br />
auto x = a[(){ return $-1; }()];<br />
// Error: cannnot use $ inside a function literal<br />
</syntaxhighlight><br />
</ol><br />
<br />
Therefore,<br />
<syntaxhighlight lang="d"><br />
auto x = a[(){<br />
if (auto {1, $} = tup) { // '$' is always *pattern placeholder*<br />
...<br />
}<br />
return 0;<br />
}];<br />
</syntaxhighlight><br />
<br />
<dt><code>$identifier</code> meaning for pattern matching<br />
<dd><br />
$identifier is used for the special syntax for pattern matching.<br />
Inside pattern, bare <code>identifier</code> will always make placeholder.<br />
<syntaxhighlight lang="d"><br />
if (auto {x, y} = coord) {<br />
// x and y captures coord's elements only in 'then' statement.<br />
}<br />
</syntaxhighlight><br />
<br />
If newly declared valiable conflicts with outer variables, it is refused.<br />
<syntaxhighlight lang="d"><br />
int x = 1;<br />
if (auto {x, y} = coord) { auto x2 = x; } // error, ambiguous 'x' usage<br />
</syntaxhighlight><br />
<br />
If you want to make a pattern with evaluating variable, use <code>$identifier</code>.<br />
<syntaxhighlight lang="d"><br />
int x = 1;<br />
if (auto {$x, y} = coord) { ... }<br />
// If the first element of coord is equal to 1 (== x), 'then' statement wil be evaluated.<br />
</syntaxhighlight><br />
<br />
</dl><br />
<br />
=== Unpacking and tuple expansion ===<br />
<br />
Unpacking implicitly requires tuple for its operand, so it can be automatically expanded.<br />
<syntaxhighlight lang="d"><br />
auto coord = {1, 2};<br />
if (auto {x, y} = coord) {}<br />
if (auto {x, y} = coord[]) {} // same, explicitly expands fields<br />
</syntaxhighlight><br />
<br />
=== Mismatching tuple element types and length ===<br />
<br />
<syntaxhighlight lang="d"><br />
auto tup = {1, "hi"}<br />
if (auto {num} = tup) {} // compile error<br />
if (auto {num, msg, x} = tup) {} // compile error<br />
if ({string num, int msg} = tup) {} // compile error<br />
<br />
if (auto {num, msg, ...} = tup) {} // ok, `...` matches to zero-elements.<br />
</syntaxhighlight><br />
<br />
<!--<br />
== TODO ==<br />
<br />
The things written in this section are not yet well defined, so they might be removed later.<br />
<br />
=== Tuple fields are always unnamed ===<br />
<br />
<syntaxhighlight lang="d"><br />
// The types of tuples which have field names<br />
alias MyPair = typeof({1, "hi"});<br />
alias MyRecord = typeof({count:1, msg:"hi"});<br />
static assert(is(MyPair == MyRecord)); // true or false?<br />
static assert(is(MyPair : MyRecord)); // true or false?<br />
static assert(is(MyRecord : MyPair)); // true or false?<br />
alias MyStudent = typeof({num:1, name:"John"});<br />
static assert(is(MyRecord == MyStudent)); // true or false?<br />
<br />
// named pattern is mostly useless<br />
if (auto {num:1, msg:"hi"} = pair) {}<br />
</syntaxhighlight><br />
<br />
=== Unpacking fields from object ===<br />
<br />
<syntaxhighlight lang="d"><br />
auto tup = {obj.a, obj.b, obj.c}<br />
is shorten to:<br />
auto tup = obj.{a, b, c}<br />
<br />
auto tup = {obj.a, obj.b.x, obj.b.y, obj.c}<br />
is shorten to:<br />
auto tup = obj.{a, b.{x, y}[], c}<br />
</syntaxhighlight><br />
<br />
* With `obj.{...}`, can guarantee that `obj` will be evaluated once.<br />
* The result of `obj.{...}` always makes a tuple.<br />
It is essential limitation that comes from the syntax .<br />
--><br />
<br />
== Use case of uniform tuple syntax ==<br />
<br />
Original D code:<br />
Source: http://forum.dlang.org/post/gridjorxqlpoytuxwpsg@forum.dlang.org<br />
<br />
<syntaxhighlight lang="d"><br />
import std.stdio, std.algorithm, std.typecons, std.container, std.array;<br />
<br />
auto encode(T)(Group!("a == b", T[]) sf) {<br />
auto heap = sf.map!(s => tuple(s[1], [tuple(s[0], "")]))<br />
.array.heapify!q{b < a};<br />
<br />
while (heap.length > 1) {<br />
auto lo = heap.front; heap.removeFront;<br />
auto hi = heap.front; heap.removeFront;<br />
foreach (ref pair; lo[1]) pair[1] = '0' ~ pair[1];<br />
foreach (ref pair; hi[1]) pair[1] = '1' ~ pair[1];<br />
heap.insert(tuple(lo[0] + hi[0], lo[1] ~ hi[1]));<br />
}<br />
return heap.front[1].schwartzSort!q{tuple(a[1].length, a[0])};<br />
}<br />
<br />
void main() {<br />
auto s = "this is an example for huffman encoding"d;<br />
foreach (p; s.dup.sort().release.group.encode)<br />
writefln("'%s' %s", p[]);<br />
}<br />
</syntaxhighlight><br />
<br />
<br />
This proposal:<br />
<br />
<syntaxhighlight lang="d"><br />
import std.stdio, std.algorithm, std.container, std.array;<br />
<br />
auto encode(T)(Group!("a == b", T[]) sf) {<br />
auto heap = sf.map!({c, f} => {f, [{c, ""}]}).array.heapify!q{b < a};<br />
<br />
while (heap.length > 1) {<br />
auto {lof, loa} = heap.front; heap.removeFront;<br />
auto {hif, hia} = heap.front; heap.removeFront;<br />
<br />
foreach ({$, ref e}; loa) e = '0' ~ e;<br />
foreach ({$, ref e}; hia) e = '1' ~ e;<br />
heap.insert({lof + hif, loa ~ hia});<br />
}<br />
<br />
return heap.front[1].schwartzSort!({c, e} => {e.length, c});<br />
}<br />
<br />
void main() {<br />
auto s = "this is an example for huffman encoding"d;<br />
foreach ({c, e}; s.dup.sort().release.group.encode)<br />
writefln("'%s' %s", c, e);<br />
}<br />
</syntaxhighlight><br />
<br />
<br />
Basic () syntax, perhaps the cleanest, but can't be used:<br />
<br />
<syntaxhighlight lang="d"><br />
import std.stdio, std.algorithm, std.container, std.array;<br />
<br />
auto encode(T)(Group!("a == b", T[]) sf) {<br />
auto heap = sf.map!((c, f) => (f, [(c, "")])).array.heapify!q{b < a};<br />
<br />
while (heap.length > 1) {<br />
auto (lof, loa) = heap.front; heap.removeFront;<br />
auto (hif, hia) = heap.front; heap.removeFront;<br />
foreach ((_, ref e); loa) e = '0' ~ e;<br />
foreach ((_, ref e); hia) e = '1' ~ e;<br />
heap.insert((lof + hif, loa ~ hia));<br />
}<br />
return heap.front[1].schwartzSort!((c, e) => (e.length, c));<br />
}<br />
<br />
void main() {<br />
auto s = "this is an example for huffman encoding"d;<br />
foreach ((c, e); s.dup.sort().release.group.encode)<br />
writefln("'%s' %s", c, e);<br />
}<br />
</syntaxhighlight><br />
<br />
<br />
tuple() syntax, clear, a bit long:<br />
<br />
<syntaxhighlight lang="d"><br />
import std.stdio, std.algorithm, std.container, std.array;<br />
<br />
auto encode(T)(Group!("a == b", T[]) sf) {<br />
auto heap = sf.map!(tuple(c, f) => tuple(f, [tuple(c, "")]))<br />
.array.heapify!q{b < a};<br />
<br />
while (heap.length > 1) {<br />
auto tuple(lof, loa) = heap.front; heap.removeFront;<br />
auto tuple(hif, hia) = heap.front; heap.removeFront;<br />
foreach (tuple(_, ref e); loa) e = '0' ~ e;<br />
foreach (tuple(_, ref e); hia) e = '1' ~ e;<br />
heap.insert(tuple(lof + hif, loa ~ hia));<br />
}<br />
return heap.front[1].schwartzSort!(tuple(c, e) => tuple(e.length, c));<br />
}<br />
<br />
void main() {<br />
auto s = "this is an example for huffman encoding"d;<br />
foreach (tuple(c, e); s.dup.sort().release.group.encode)<br />
writefln("'%s' %s", c, e);<br />
}<br />
</syntaxhighlight><br />
<br />
<br />
@{} syntax, noisy:<br />
<br />
<syntaxhighlight lang="d"><br />
import std.stdio, std.algorithm, std.container, std.array;<br />
<br />
auto encode(T)(Group!("a == b", T[]) sf) {<br />
auto heap = sf.map!(@{c, f} => {f, [@{c, ""}]}).array.heapify!q{b < a};<br />
<br />
while (heap.length > 1) {<br />
auto @{lof, loa} = heap.front; heap.removeFront;<br />
auto @{hif, hia} = heap.front; heap.removeFront;<br />
foreach (@{_, ref e}; loa) e = '0' ~ e;<br />
foreach (@{_, ref e}; hia) e = '1' ~ e;<br />
heap.insert(@{lof + hif, loa ~ hia});<br />
}<br />
return heap.front[1].schwartzSort!(@{c, e} => @{e.length, c});<br />
}<br />
<br />
void main() {<br />
auto s = "this is an example for huffman encoding"d;<br />
foreach (@{c, e}; s.dup.sort().release.group.encode)<br />
writefln("'%s' %s", c, e);<br />
}<br />
</syntaxhighlight><br />
<br />
<br />
<br />
(||) banana syntax, a bit confusing, but IDEs can visualize (| and |) as some nice Unicode glyps:<br />
<br />
<syntaxhighlight lang="d"><br />
import std.stdio, std.algorithm, std.container, std.array;<br />
<br />
auto encode(T)(Group!("a == b", T[]) sf) {<br />
auto heap = sf.map!((|c, f|) => (|f, [(|c, ""|)]|)).array.heapify!q{b < a};<br />
<br />
while (heap.length > 1) {<br />
auto (|lof, loa|) = heap.front; heap.removeFront;<br />
auto (|hif, hia|) = heap.front; heap.removeFront;<br />
foreach ((|_, ref e|); loa) e = '0' ~ e;<br />
foreach ((|_, ref e|); hia) e = '1' ~ e;<br />
heap.insert((|lof + hif, loa ~ hia|));<br />
}<br />
return heap.front[1].schwartzSort!((|c, e|) => (|e.length, c|));<br />
}<br />
<br />
void main() {<br />
auto s = "this is an example for huffman encoding"d;<br />
foreach ((|c, e|); s.dup.sort().release.group.encode)<br />
writefln("'%s' %s", c, e);<br />
}<br />
</syntaxhighlight><br />
<br />
<br />
t{} syntax, the t is not very easy to see, but it's short and it's similar to the q{} for token strings:<br />
<br />
<syntaxhighlight lang="d"><br />
import std.stdio, std.algorithm, std.container, std.array;<br />
<br />
auto encode(T)(Group!("a == b", T[]) sf) {<br />
auto heap = sf.map!(t{c, f} => {f, [t{c, ""}]}).array.heapify!q{b < a};<br />
<br />
while (heap.length > 1) {<br />
auto t{lof, loa} = heap.front; heap.removeFront;<br />
auto t{hif, hia} = heap.front; heap.removeFront;<br />
foreach (t{_, ref e}; loa) e = '0' ~ e;<br />
foreach (t{_, ref e}; hia) e = '1' ~ e;<br />
heap.insert(t{lof + hif, loa ~ hia});<br />
}<br />
return heap.front[1].schwartzSort!(t{c, e} => t{e.length, c});<br />
}<br />
<br />
void main() {<br />
auto s = "this is an example for huffman encoding"d;<br />
foreach (t{c, e}; s.dup.sort().release.group.encode)<br />
writefln("'%s' %s", c, e);<br />
}<br />
</syntaxhighlight><br />
<br />
== Copyright ==<br />
<br />
This document has been placed in the Public Domain.</div>
Bearophile