www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Worst ideas/features in programming languages?

reply Atila Neves <atila.neves gmail.com> writes:
I'm brainstorming about what I'll talk about at DConf, and during 
a conversation with Walter I thought it might be cool to talk 
about:

* Worst features implemented in a non-toy language
* Worst features (in your opinion) in D
* Features you'd like to see in D

Ideas? Examples?

Thanks!
Oct 11 2021
next sibling parent reply FeepingCreature <feepingcreature gmail.com> writes:
On Monday, 11 October 2021 at 15:59:10 UTC, Atila Neves wrote:
 I'm brainstorming about what I'll talk about at DConf, and 
 during a conversation with Walter I thought it might be cool to 
 talk about:

 * Worst features implemented in a non-toy language
 * Worst features (in your opinion) in D
 * Features you'd like to see in D

 Ideas? Examples?

 Thanks!
Objectively worst feature: mutability/referenceability by default. It takes away *so* much optimization potential and introduces so many opportunities for state changes. `var = value` should be opt-in. Just as importantly, `&var` should be opt-in. My D hobbyhorse, of course, is `__traits(compiles)` (see my last DConf talk) and the SFINAE-like mess that it enables but doesn't give us the tools to address. "Why did the template not instantiate?" Who knows~ That syntax error got suppressed five instantiations down. And there's obvious stuff like the half-baked `immutable` that works in about half the stdlib and a smaller fraction of libraries. D2 const was a mistake, cmv. (Nonreferenceability allows safe reassignment of immutable struct member fields, btw!) But I'm actually convinced that the worst thing is the lack of implicit construction for sumtypes. Because when you try to actually use sumtypes, you end up with stuff like `Nullable!MySumType(MySumType(MemberType("Hello World")))`. *All over the place.* And it adds no value! The whole point of `MySumType` is that it's "one of n types, including `MemberType`". Writing out the full type of a nested container type like that adds nothing of value. Sumtypes should be built-in, and they should implicitly construct from its member types. PS: But staring at this post interface, what I want the most *right now* - a "Discard all drafts" button. :)
Oct 11 2021
parent reply russhy <russhy gmail.com> writes:
On Monday, 11 October 2021 at 16:12:59 UTC, FeepingCreature wrote:
 On Monday, 11 October 2021 at 15:59:10 UTC, Atila Neves wrote:
 I'm brainstorming about what I'll talk about at DConf, and 
 during a conversation with Walter I thought it might be cool 
 to talk about:

 * Worst features implemented in a non-toy language
 * Worst features (in your opinion) in D
 * Features you'd like to see in D

 Ideas? Examples?

 Thanks!
Objectively worst feature: mutability/referenceability by default. It takes away *so* much optimization potential and introduces so many opportunities for state changes. `var = value` should be opt-in. Just as importantly, `&var` should be opt-in. My D hobbyhorse, of course, is `__traits(compiles)` (see my last DConf talk) and the SFINAE-like mess that it enables but doesn't give us the tools to address. "Why did the template not instantiate?" Who knows~ That syntax error got suppressed five instantiations down. And there's obvious stuff like the half-baked `immutable` that works in about half the stdlib and a smaller fraction of libraries. D2 const was a mistake, cmv. (Nonreferenceability allows safe reassignment of immutable struct member fields, btw!) But I'm actually convinced that the worst thing is the lack of implicit construction for sumtypes. Because when you try to actually use sumtypes, you end up with stuff like `Nullable!MySumType(MySumType(MemberType("Hello World")))`. *All over the place.* And it adds no value! The whole point of `MySumType` is that it's "one of n types, including `MemberType`". Writing out the full type of a nested container type like that adds nothing of value. Sumtypes should be built-in, and they should implicitly construct from its member types. PS: But staring at this post interface, what I want the most *right now* - a "Discard all drafts" button. :)
- features that require a GC (associative array) - class (reference type)
 Sumtypes should be built-in, and they should implicitly 
 construct from its member types.
I 100% agree with you Tagged union SHOULD be built in, telling people to import a package and use them like templates is the best way to discourage people from getting interested in the language When other "modern" languages don't have the problem since it's built in feature The positive side of std.sumtype is it showcase the capabilities of the language to implement new features on user land, BUT, for sumtype, nobody should have to go that road.. Same for Nullable/Optional in my opinion
Oct 11 2021
parent reply James Blachly <james.blachly gmail.com> writes:
On 10/11/21 1:35 PM, russhy wrote:
 On Monday, 11 October 2021 at 16:12:59 UTC, FeepingCreature wrote:
 On Monday, 11 October 2021 at 15:59:10 UTC, Atila Neves wrote:
 Sumtypes should be built-in, and they should implicitly construct from 
 its member types.
I 100% agree with you
100%. I am really loving Ilya's `mir.algebraic` for my sumtype needs: http://mir-core.libmir.org/mir_algebraic.html
 Same for Nullable/Optional in my opinion
Likewise mir algebraic has Nullable. But what it (and D overall as a builtin) is really missing is Result type (with Ok and Err tags) -- will be eagerly checking out Chaloupka's `expected` package soon. PS:
 But I'm actually convinced that the worst thing is the lack of
 implicit construction for sumtypes. Because when you try to actually
 use sumtypes, you end up with stuff like
 `Nullable!MySumType(MySumType(MemberType("Hello World")))`.
https://run.dlang.io/is/XUtxwm :)
Oct 11 2021
next sibling parent reply Paul Backus <snarwin gmail.com> writes:
On Monday, 11 October 2021 at 20:41:33 UTC, James Blachly wrote:
 Likewise mir algebraic has Nullable. But what it (and D overall 
 as a builtin) is really missing is Result type (with Ok and Err 
 tags) -- will be eagerly checking out Chaloupka's `expected` 
 package soon.
The real missing piece here IMO is DIP 1038 [1]. Once it is fully accepted and implemented, defining a Result type will be trivial. [1] https://github.com/dlang/DIPs/blob/b30b94d40bd76b513d31509f8e40f7c38d111929/DIPs/DIP1038.md
Oct 11 2021
parent reply Nick Treleaven <nick geany.org> writes:
On Monday, 11 October 2021 at 21:21:21 UTC, Paul Backus wrote:
 The real missing piece here IMO is DIP 1038 [1]. Once it is 
 fully accepted and implemented, defining a Result type will be 
 trivial.
Could you explain how nodiscard would help with sum types? Presumably it won't help to implicitly convert a subtype into the wrapper sum type?
Oct 12 2021
parent reply Paul Backus <snarwin gmail.com> writes:
On Tuesday, 12 October 2021 at 16:19:42 UTC, Nick Treleaven wrote:
 On Monday, 11 October 2021 at 21:21:21 UTC, Paul Backus wrote:
 The real missing piece here IMO is DIP 1038 [1]. Once it is 
 fully accepted and implemented, defining a Result type will be 
 trivial.
Could you explain how nodiscard would help with sum types? Presumably it won't help to implicitly convert a subtype into the wrapper sum type?
Currently, the big advantage exceptions have over sum types is that you cannot accidentally ignore an exception. Either you catch it, or it crashes your program. With ` nodiscard`, we can eliminate this advantage, and put sum types and exceptions on an equal playing field.
Oct 12 2021
parent reply max haughton <maxhaton gmail.com> writes:
On Tuesday, 12 October 2021 at 16:26:33 UTC, Paul Backus wrote:
 On Tuesday, 12 October 2021 at 16:19:42 UTC, Nick Treleaven 
 wrote:
 On Monday, 11 October 2021 at 21:21:21 UTC, Paul Backus wrote:
 The real missing piece here IMO is DIP 1038 [1]. Once it is 
 fully accepted and implemented, defining a Result type will 
 be trivial.
Could you explain how nodiscard would help with sum types? Presumably it won't help to implicitly convert a subtype into the wrapper sum type?
Currently, the big advantage exceptions have over sum types is that you cannot accidentally ignore an exception. Either you catch it, or it crashes your program. With ` nodiscard`, we can eliminate this advantage, and put sum types and exceptions on an equal playing field.
One idea I had when bumping into this problem was something like a with statement but you give it some kind of composition operator, and then it joins the statements up implicitly a la do notation in Haskell
Oct 12 2021
parent reply Paul Backus <snarwin gmail.com> writes:
On Tuesday, 12 October 2021 at 17:25:52 UTC, max haughton wrote:
 One idea I had when bumping into this problem was something 
 like a with statement but you give it some kind of composition 
 operator, and then it joins the statements up implicitly a la 
 do notation in Haskell
You can technically do this already with `foreach` and `opApply`, although the result ends up looking kind of goofy: ```d foreach (b; a) foreach (c; b) foreach (d; c) e; ``` Desugars to: ```d a.opApply(b => b.opApply(c => c.opApply(d => e))); ``` ...which is almost the same thing as Haskell's `do` notation, if you replace `>>=` with `opApply` and `x <- y` with `foreach (x, y)`. This similarity is perhaps why Scala uses the `for` keyword for [its version of `do` notation][1]. [1]: https://docs.scala-lang.org/tour/for-comprehensions.html
Oct 12 2021
parent max haughton <maxhaton gmail.com> writes:
On Tuesday, 12 October 2021 at 17:48:04 UTC, Paul Backus wrote:
 On Tuesday, 12 October 2021 at 17:25:52 UTC, max haughton wrote:
 [...]
You can technically do this already with `foreach` and `opApply`, although the result ends up looking kind of goofy: ```d foreach (b; a) foreach (c; b) foreach (d; c) e; ``` Desugars to: ```d a.opApply(b => b.opApply(c => c.opApply(d => e))); ``` ...which is almost the same thing as Haskell's `do` notation, if you replace `>>=` with `opApply` and `x <- y` with `foreach (x, y)`. This similarity is perhaps why Scala uses the `for` keyword for [its version of `do` notation][1]. [1]: https://docs.scala-lang.org/tour/for-comprehensions.html
I hate this and I hate you! Nice trick though, wouldn't have thought to do that.
Oct 12 2021
prev sibling parent 9il <ilyayaroshenko gmail.com> writes:
On Monday, 11 October 2021 at 20:41:33 UTC, James Blachly wrote:
 But I'm actually convinced that the worst thing is the lack of
 implicit construction for sumtypes. Because when you try to 
 actually
 use sumtypes, you end up with stuff like
 `Nullable!MySumType(MySumType(MemberType("Hello World")))`.
https://run.dlang.io/is/XUtxwm :)
Maybe you mean that one? https://run.dlang.io/is/zw1Ekq
Oct 12 2021
prev sibling next sibling parent reply Johan <j j.nl> writes:
On Monday, 11 October 2021 at 15:59:10 UTC, Atila Neves wrote:
 I'm brainstorming about what I'll talk about at DConf, and 
 during a conversation with Walter I thought it might be cool to 
 talk about:

 * Worst features implemented in a non-toy language
 * Worst features (in your opinion) in D
Two things that immediately come to mind: - `unittest`. Clutters code reading, discourages extensive testing (because of said clutter), discourages testing inside a user's module, complicates runtime and compiler, framework cannot be developed separate from language runtime, ... - Implicit pointer/reference type of classes. While I think the forced reference type of classes is a good idea (when passing as function argument), I think it was a very bad idea to remove the `*` from notation. It makes code impossible to interpret without looking up a user-defined type. -Johan
Oct 11 2021
parent jmh530 <john.michael.hall gmail.com> writes:
On Monday, 11 October 2021 at 17:06:38 UTC, Johan wrote:
 [snip]

 - `unittest`. Clutters code reading, discourages extensive 
 testing (because of said clutter), discourages testing inside a 
 user's module, complicates runtime and compiler, framework 
 cannot be developed separate from language runtime, ...
Nothing prevents you from pulling out the unittests (except maybe documented ones) and putting them in a separate file or folder structure. In fact, it should probably be more commonly done...
Oct 11 2021
prev sibling next sibling parent jfondren <julian.fondren gmail.com> writes:
On Monday, 11 October 2021 at 15:59:10 UTC, Atila Neves wrote:
 I'm brainstorming about what I'll talk about at DConf, and 
 during a conversation with Walter I thought it might be cool to 
 talk about:

 * Worst features implemented in a non-toy language
Indirect method notation in Perl: https://stackoverflow.com/questions/11695110/why-is-this-program-valid-i-was-trying-to-create-a-syntax-error/11695310#11695310 wantarray in Perl, where e.g. reverse() either reverses its list of arguments (a list of one argument $a in the following program--a noop) or it reverses the joined string of its list of arguments (the single string $a in the following the program) , depending on what the caller wants: ```perl sub foo { my ($a) = _; reverse $a; } my $changed = foo("changed"); ``` Aliasing subroutine parameters in Perl: `sub foo { my $arg = shift; }` is not the same thing as `sub foo { my ($arg) = _; }` and I can no longer remember why it's super critically important that you use the second form by default. Autovivification in Perl - usually desirable, and D has it to an extent in AAs. But then there's this: ```perl sub add { my ($table, $key) = _; $table->{$key} = 1; } within add() die "that silently did nothing" if exists $table{one}; print $table{two}; ``` Overriding 'built in' functions. Does `stat()` return the list of fields enumerated in 'perldoc -f stat' or does it return an object? Better check and see if the program you're maintaining used File::stat or not. $_ as the default argument in Perl. Literally once a month I write this code: ```perl open my $f, '<', 'open some file to read' or die "Tried to open 'some file to read' and failed : $!"; while (defined(my $line = <$f>)) { next unless /oh goddamnit this regex is applying to $_ and not $line/; do_stuff; } ``` Perl has a lot of "wow, that was a horrible idea! Let's fix it by adding a new syntax, encouraging people to use that instead, and then leaving this horrible idea in the language forever." misfeatures. The separate '<' in the previous example is some new syntax for opening files. The old syntax lets you write tools that will truncate /etc/passwd or spawn arbitrary subprocesses if given a malicious filename. At least those dangerous tools never stopped working due to the language updating and breaking them, right?
 * Worst features (in your opinion) in D
 * Features you'd like to see in D
Maybe it's not surprising by this point of this post, but I'm pretty happy with D. I would like some easy way to make sure I haven't accidentally used 80-bit floats in a D program.
Oct 11 2021
prev sibling next sibling parent reply Dukc <ajieskola gmail.com> writes:
On Monday, 11 October 2021 at 15:59:10 UTC, Atila Neves wrote:
 I'm brainstorming about what I'll talk about at DConf, and 
 during a conversation with Walter I thought it might be cool to 
 talk about:

 * Worst features implemented in a non-toy language
- Some C standard library functions. `gets` is the worst one, but `atof` and `atoi` are pretty useless too. - The feature of some early C compilers that only the first 7 characters of an identifier are significant. - C casting and C++ template syntaxes.
 * Worst features (in your opinion) in D
- Integer promotion without at least letting to assign the result back to original width without a cast - Autodecoding. It would not be as bad if string literals were of some sort of wrapper type over the data, but autodecoding a plain array type just sucks.
 * Features you'd like to see in D
- The Phobos versioning scheme that is already in the works. - Some way to enable preview/revert switches per module as opposed to per compilation. And same for autodecoding if possible. - More compatibility between compiler / standard library versions in general.
 Ideas? Examples?
- Perhaps we should have a common agreement on what compiler versions should be used when long-term support for code is the goal. For example, we could agree on 2.084, 2.090, 2.096, 2.102 etc.
Oct 11 2021
parent reply russhy <russhy gmail.com> writes:
 Worst features implemented in a non-toy language
It's been a while i haven't used anything other than D, so i don't have much to say, i'll need to research to remember first On top of my head, i think the worst feature in any language is C/C++ header system Sometimes, in rare occasions it can be handy, but most of the time it is a pain in the butt
 Worst features (in your opinion) in D
- class (reference type) - GC as a feature - !() for templates (not really a feature, more like a syntax issue, way to similar to functions) - being abot to use ! with optional parentheses, countless times i got bit by: ``Array!int* array;`` but i wanted ``Array!(int)* array;`` instead..
 Features you'd like to see in D
- tagged union (built in, not as std/lib) - interface / signature for structs (built in, not as std/lib) - alternatively, reintroduce the * for classes - enum literals (being able to omit the enum name) ex: ```d enum MyEnum { A, B, C} MyEnum e = :A; my_function(:A); switch (e) { case :A: break; } // could be :, ., $, ! but that is not the point '''
Oct 11 2021
next sibling parent reply 12345swordy <alexanderheistermann gmail.com> writes:
On Monday, 11 October 2021 at 18:27:29 UTC, russhy wrote:
 Worst features implemented in a non-toy language
- GC as a feature
This GC phobia is hurting the d language.
 - class (reference type)
WHY!? -Alex
Oct 11 2021
next sibling parent 12345swordy <alexanderheistermann gmail.com> writes:
On Monday, 11 October 2021 at 18:27:29 UTC, russhy wrote:
 Worst features implemented in a non-toy language
- GC as a feature
This GC phobia is hurting the d language.
 - class (reference type)
WHY!? -Alex Fix formating
Oct 11 2021
prev sibling next sibling parent reply russhy <russhy gmail.com> writes:
On Monday, 11 October 2021 at 20:48:47 UTC, 12345swordy wrote:
 On Monday, 11 October 2021 at 18:27:29 UTC, russhy wrote:
 Worst features implemented in a non-toy language
- GC as a feature
This GC phobia is hurting the d language.
 - class (reference type)
WHY!? -Alex
it is not GC phobia, i use the GC for some projects and i'm ok with it it just is when you don't need it, you need to be careful with nogc, and there is no way to globally enforce a nogc behavior these issues would be solved if GC was introduced as a library, or as a toggleable feature without having to resort to -betterC GC, even thought i don't like the comparison myself, D still is a system language Countless hours wasted working aroung GC limitations with Unity If they had went with D, they wouldn't have to be this careful with their language! an area D should have won market share (engine code + scripting code at the same time!)
Oct 11 2021
parent Nicholas Wilson <iamthewilsonator hotmail.com> writes:
On Monday, 11 October 2021 at 21:38:17 UTC, russhy wrote:
 it just is when you don't need it, you need to be careful with 
  nogc, and there is no way to globally enforce a  nogc behavior
try a ` nogc` main() function. Yes this doesn't handle module global and thread constructors, but its global enough.
Oct 11 2021
prev sibling parent reply russhy <russhy gmail.com> writes:
On Monday, 11 October 2021 at 20:48:47 UTC, 12345swordy wrote:
 On Monday, 11 October 2021 at 18:27:29 UTC, russhy wrote:
 Worst features implemented in a non-toy language
- GC as a feature
This GC phobia is hurting the d language.
 - class (reference type)
WHY!? -Alex
because, as other said, it is hard to differentiate from struct (values), you always have to check the symbol signature, wich is just annoying ``void pass(MyType* type) {}`` ``void pass(MyType type) {}`` you can't know what is a type or the pointer of a reference type, having to guess / context switch to go check symbol signature is a pain
Oct 12 2021
parent 12345swordy <alexanderheistermann gmail.com> writes:
On Wednesday, 13 October 2021 at 01:56:06 UTC, russhy wrote:
 On Monday, 11 October 2021 at 20:48:47 UTC, 12345swordy wrote:
 On Monday, 11 October 2021 at 18:27:29 UTC, russhy wrote:
 Worst features implemented in a non-toy language
- GC as a feature
This GC phobia is hurting the d language.
 - class (reference type)
WHY!? -Alex
because, as other said, it is hard to differentiate from struct (values), you always have to check the symbol signature, wich is just annoying
It is not an issue if you have a functional IDE that does the heavy lifting for you. This isn't a language issue here. You are doing something very wrong if you find yourself typing
void pass(Mytype* type) {}
where Mytype is a class. This is not c++ here. -Alex
Oct 13 2021
prev sibling next sibling parent Atila Neves <atila.neves gmail.com> writes:
On Monday, 11 October 2021 at 18:27:29 UTC, russhy wrote:
 [...]
It's been a while i haven't used anything other than D, so i don't have much to say, i'll need to research to remember first [...]
The enum thing works now: ``` enum MyEnum { A, B, C} with(MyEnum) { auto e = A; myFunction(A); switch(e) { case A: break; default: } } ```
Oct 14 2021
prev sibling parent reply Dr Machine Code <jckj33 gmail.com> writes:
On Monday, 11 October 2021 at 18:27:29 UTC, russhy wrote:

[...]

 Features you'd like to see in D
- tagged union (built in, not as std/lib) - interface / signature for structs (built in, not as std/lib) - alternatively, reintroduce the * for classes - enum literals (being able to omit the enum name) ex: ```d enum MyEnum { A, B, C} MyEnum e = :A; my_function(:A); switch (e) { case :A: break; } // could be :, ., $, ! but that is not the point '''
This unscoped enums is one of the worst features in C/C++, imho. I loved when I switch to languages that the enum got its scopre but D you got both, you can also do: ```D enum A = 0; enum B = 1; // ... ``` if you dislike to set their initial values manually, I think you can write a template function to create enum values
Nov 14 2021
parent reply russhy <russhy gmail.com> writes:
On Sunday, 14 November 2021 at 18:41:10 UTC, Dr Machine Code 
wrote:
 On Monday, 11 October 2021 at 18:27:29 UTC, russhy wrote:

 [...]

 Features you'd like to see in D
- tagged union (built in, not as std/lib) - interface / signature for structs (built in, not as std/lib) - alternatively, reintroduce the * for classes - enum literals (being able to omit the enum name) ex: ```d enum MyEnum { A, B, C} MyEnum e = :A; my_function(:A); switch (e) { case :A: break; } // could be :, ., $, ! but that is not the point '''
This unscoped enums is one of the worst features in C/C++, imho. I loved when I switch to languages that the enum got its scopre but D you got both, you can also do: ```D enum A = 0; enum B = 1; // ... ``` if you dislike to set their initial values manually, I think you can write a template function to create enum values
It's not unscoped, it type checked, it just removes the need to be verbose and repetitive ```D MyAbility ability; switch (ability) { case MyAbility.SOMETHING_1: break; case MyAbility.SOMETHING_2: break; case MyAbility.SOMETHING_3: break; case MyAbility.SOMETHING_4: break; case MyAbility.SOMETHING_5: break; } ``` What this repetition solves? ```D void use_ability(MyAbility ability){} use_ability(MyAbility.SOMETHING_1); ``` Imagine if you had to prefix the type of everything ```D void use_my_int(int a) {} use_my_int(int.4545846846); ``` Compiler can be smarter Languages that allow removing the prefix for enums are popular it helps a lot with readability
Nov 15 2021
parent reply "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Mon, Nov 15, 2021 at 05:25:35PM +0000, russhy via Digitalmars-d wrote:
[...]
 ```D
 MyAbility ability;
 
 switch (ability)
 {
  case MyAbility.SOMETHING_1: break;
  case MyAbility.SOMETHING_2: break;
  case MyAbility.SOMETHING_3: break;
  case MyAbility.SOMETHING_4: break;
  case MyAbility.SOMETHING_5: break;
 }
 ```
 
 
 What this repetition solves?
[...] Why can't you just write: MyAbility ability; switch (ability) with(MyAbility) { case SOMETHING_1: break; case SOMETHING_2: break; case SOMETHING_3: break; case SOMETHING_4: break; case SOMETHING_5: break; } ? The `with` keyword was designed specifically for this purpose. T -- They pretend to pay us, and we pretend to work. -- Russian saying
Nov 15 2021
next sibling parent reply kdevel <kdevel vogtner.de> writes:
On Monday, 15 November 2021 at 17:48:35 UTC, H. S. Teoh wrote:
[...]
 Why can't you just write:

 	MyAbility ability;

 	switch (ability) with(MyAbility)
 	{
 	 case SOMETHING_1: break;
 	 case SOMETHING_2: break;
 	 case SOMETHING_3: break;
 	 case SOMETHING_4: break;
 	 case SOMETHING_5: break;
 	}

 ?  The `with` keyword was designed specifically for this 
 purpose.
Nice. What about import std.stdio; enum SAB { a = 1, } void main () { with (SAB) if (a == 1) writeln ("true"); with (SAB) void foo () { writeln (a); } // no complaints! foo(); // Error: undefined identifier `foo` }
Nov 15 2021
parent reply "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Mon, Nov 15, 2021 at 09:10:51PM +0000, kdevel via Digitalmars-d wrote:
 On Monday, 15 November 2021 at 17:48:35 UTC, H. S. Teoh wrote:
 [...]
 Why can't you just write:
 
 	MyAbility ability;
 
 	switch (ability) with(MyAbility)
 	{
 	 case SOMETHING_1: break;
 	 case SOMETHING_2: break;
 	 case SOMETHING_3: break;
 	 case SOMETHING_4: break;
 	 case SOMETHING_5: break;
 	}
 
 ?  The `with` keyword was designed specifically for this purpose.
Nice. What about import std.stdio; enum SAB { a = 1, } void main () { with (SAB) if (a == 1) writeln ("true"); with (SAB) void foo () { writeln (a); } // no complaints! foo(); // Error: undefined identifier `foo` }
[...] That's because `with` introduces a scope. So you should have written instead: void foo () { with (SAB) writeln (a); } Or, for that matter: void main () { with (SAB) { if (a == 1) writeln ("true"); void foo () { writeln (a); } foo(); // Now this works } } T -- Being able to learn is a great learning; being able to unlearn is a greater learning.
Nov 15 2021
parent russhy <russhy gmail.com> writes:
On Monday, 15 November 2021 at 21:23:56 UTC, H. S. Teoh wrote:
 On Mon, Nov 15, 2021 at 09:10:51PM +0000, kdevel via 
 Digitalmars-d wrote:
 On Monday, 15 November 2021 at 17:48:35 UTC, H. S. Teoh wrote: 
 [...]
 Why can't you just write:
 
 	MyAbility ability;
 
 	switch (ability) with(MyAbility)
 	{
 	 case SOMETHING_1: break;
 	 case SOMETHING_2: break;
 	 case SOMETHING_3: break;
 	 case SOMETHING_4: break;
 	 case SOMETHING_5: break;
 	}
 
 ?  The `with` keyword was designed specifically for this 
 purpose.
Nice. What about import std.stdio; enum SAB { a = 1, } void main () { with (SAB) if (a == 1) writeln ("true"); with (SAB) void foo () { writeln (a); } // no complaints! foo(); // Error: undefined identifier `foo` }
[...] That's because `with` introduces a scope. So you should have written instead: void foo () { with (SAB) writeln (a); } Or, for that matter: void main () { with (SAB) { if (a == 1) writeln ("true"); void foo () { writeln (a); } foo(); // Now this works } } T
that's not what i am asking - now you leak SAB scope everywhere - now you have to indent everything - there is no differenciation between SAB.a and a variable called a Why make things complicated and bloated when it can be simple? Also why making me want to want something that is not what i asked? it's quite the opposite!
Nov 15 2021
prev sibling parent russhy <russhy gmail.com> writes:
On Monday, 15 November 2021 at 17:48:35 UTC, H. S. Teoh wrote:
 On Mon, Nov 15, 2021 at 05:25:35PM +0000, russhy via 
 Digitalmars-d wrote: [...]
 ```D
 MyAbility ability;
 
 switch (ability)
 {
  case MyAbility.SOMETHING_1: break;
  case MyAbility.SOMETHING_2: break;
  case MyAbility.SOMETHING_3: break;
  case MyAbility.SOMETHING_4: break;
  case MyAbility.SOMETHING_5: break;
 }
 ```
 
 
 What this repetition solves?
[...] Why can't you just write: MyAbility ability; switch (ability) with(MyAbility) { case SOMETHING_1: break; case SOMETHING_2: break; case SOMETHING_3: break; case SOMETHING_4: break; case SOMETHING_5: break; } ? The `with` keyword was designed specifically for this purpose. T
I don't understand your point, that is exactly what i said, a nice use of with There is a problem here, you don't listen to what i say, therefore you don't understand the problem what about ALL OTHER problems? ;) MyAbility ability switch ability with MyAbility use Ability maybe we should have a with instead of with, that'll solve the problem? /s
Nov 17 2021
prev sibling next sibling parent reply bachmeier <no spam.net> writes:
On Monday, 11 October 2021 at 15:59:10 UTC, Atila Neves wrote:
 I'm brainstorming about what I'll talk about at DConf, and 
 during a conversation with Walter I thought it might be cool to 
 talk about:

 * Worst features implemented in a non-toy language
C's pointer notation is too stupid for words. (I understand how it works. I've been using it for decades. Please no explanations.) Writing functions like this is horrible: ``` int timesTwo(int *x) { return 2 * *x; } ``` When you learn C, you ask what the `*x` is. It's an int. That makes sense. That's why it's `int *x`. Okay, let's call that function: ``` int main() { printf("%d\n", timesTwo(4)); return 0; } ``` `expected ‘int *’ but argument is of type ‘int’` Okay, let's try this: ``` int main() { int z = 4; printf("%d\n", timesTwo(&z)); return 0; } ``` `8` So `*x` is an int, but you have to pass `&z`, which is not an int, as the argument. The only way this can't be confusing to someone learning it for the first time is if they're memorizing syntax.
Oct 11 2021
next sibling parent drug <drug2004 bk.ru> writes:
On 11.10.2021 22:15, bachmeier wrote:
 On Monday, 11 October 2021 at 15:59:10 UTC, Atila Neves wrote:
 I'm brainstorming about what I'll talk about at DConf, and during a 
 conversation with Walter I thought it might be cool to talk about:

 * Worst features implemented in a non-toy language
C's pointer notation is too stupid for words. (I understand how it works. I've been using it for decades. Please no explanations.) Writing functions like this is horrible: ``` int timesTwo(int *x) {     return 2 * *x; } ``` When you learn C, you ask what the `*x` is. It's an int. That makes sense. That's why it's `int *x`. Okay, let's call that function: ``` int main() {     printf("%d\n", timesTwo(4));     return 0; } ``` `expected ‘int *’ but argument is of type ‘int’` Okay, let's try this: ``` int main() {     int z = 4;     printf("%d\n", timesTwo(&z));     return 0; } ``` `8` So `*x` is an int, but you have to pass `&z`, which is not an int, as the argument. The only way this can't be confusing to someone learning it for the first time is if they're memorizing syntax.
I would say that `x` is a pointer to int and `*x` is a dereferenced pointer to int. 4 is an int value and it can not be treated as a dereferenced pointer to int. So you need to create an int value, take the pointer to it and then pass it to the function.
Oct 11 2021
prev sibling parent reply Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= <ola.fosheim.grostad gmail.com> writes:
On Monday, 11 October 2021 at 19:15:51 UTC, bachmeier wrote:
 On Monday, 11 October 2021 at 15:59:10 UTC, Atila Neves wrote:
 I'm brainstorming about what I'll talk about at DConf, and 
 during a conversation with Walter I thought it might be cool 
 to talk about:

 * Worst features implemented in a non-toy language
C's pointer notation is too stupid for words. (I understand how it works. I've been using it for decades. Please no explanations.)
Yes, it is cultural debt, that came from a desire to express types such as a 'pointer to a pointer to an int' with a notation for keyboards with a limited set of easily accessible symbols. The cost is quite high, but people are used to. It us equally puzzeling why prople want "&&" instead of "and" or "||" instead of "or". There is no rational explanation, I think people like to feel that they are using something advanced and that a syntax that that is associated with advanced usage makes them feel more skilled? Kinda like fashion...
Oct 24 2021
next sibling parent reply SealabJaster <sealabjaster gmail.com> writes:
On Sunday, 24 October 2021 at 08:42:54 UTC, Ola Fosheim Grøstad 
wrote:
 Yes, it is cultural debt, that came from a desire to express 
 types such as a 'pointer to a pointer to an int' with a 
 notation for keyboards with a limited set of easily accessible 
 symbols. The cost is quite high, but people are used to. It us 
 equally puzzeling why prople want "&&" instead of "and" or "||" 
 instead of "or". There is no rational explanation, I think 
 people like to feel that they are using something advanced and 
 that a syntax that that is associated with advanced usage makes 
 them feel more skilled? Kinda like fashion...
I imagine && and || stem from & and |. You could probably have something like "and" and "band", "or" and "bor" but to me that doesn't seem as comfortable.
Oct 24 2021
next sibling parent SealabJaster <sealabjaster gmail.com> writes:
On Sunday, 24 October 2021 at 09:04:16 UTC, SealabJaster wrote:
 I imagine && and || stem from & and |. You could probably have 
 something like "and" and "band", "or" and "bor" but to me that 
 doesn't seem as comfortable.
Adding onto that, a "pineapple on pizza" sort of thing is that some people like to write things like `a&b|c` instead of `a & b | c`, the former I don't think is possible with keywords, but is with operators.
Oct 24 2021
prev sibling parent Ola Fosheim =?UTF-8?B?R3LDuHN0YQ==?= <ola.fosheim.grostad gmail.com> writes:
On Sunday, 24 October 2021 at 09:04:16 UTC, SealabJaster wrote:
 I imagine && and || stem from & and |. You could probably have 
 something like "and" and "band", "or" and "bor" but to me that 
 doesn't seem as comfortable.
That was why C used it, but it leads to uneccessary problems with typos, too many meanings for the symbols and overall less legible code. In terms of modelling, "&&" is used for reasoning about control flow and "&" is used for low level trickery. There is no usabilty advantage in mixing those levels visually. Also, the semantics are different as "&&" shortcuts, a point newbies tend to overlook...
Oct 24 2021
prev sibling next sibling parent reply Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= <ola.fosheim.grostad gmail.com> writes:
On Sunday, 24 October 2021 at 08:42:54 UTC, Ola Fosheim Grøstad 
wrote:
 instead of "or". There is no rational explanation, I think 
 people like to feel that they are using something advanced and 
 that a syntax that that is associated with advanced usage makes 
 them feel more skilled? Kinda like fashion...
Sorry for all the typos (ipad)... Anyway cultural impact on syntax is intersting. In the 70s/80s screens were quite limited so it made sense to write more terse code. Quite prevalent for systems work, either low level or scripting. Python did a good job of cleaning up syntax in professional programming, which is a factor in its popularity. I think elitism has a lot to do with fashions in language syntax. Like, even when BASIC would be the best tool for a job, I think many would rather not use it as it would imply being a less sophisticated programmer...
Oct 24 2021
parent reply SealabJaster <sealabjaster gmail.com> writes:
On Sunday, 24 October 2021 at 09:08:56 UTC, Ola Fosheim Grøstad 
wrote:
 I think elitism has a lot to do with fashions in language 
 syntax. Like, even when BASIC would be the best tool for a job, 
 I think many would rather not use it as it would imply being a 
 less sophisticated programmer...
This has sent me through a slightly on topic yet mostly off topic train of thought. enough and mainstream enough that there are programmers who only know those singular languages to a decent degree. Meanwhile there are the more comparatively fringe languages like D, Nim, I guess Rust, and so on, that likely consist of so-called polyglot programmers - those that are proficient in multiple languages. It's hard to express my thoughts, but I wonder what affect this has on these fringe languages in general, compared to the more mainstream ones.
Oct 24 2021
parent Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= <ola.fosheim.grostad gmail.com> writes:
On Sunday, 24 October 2021 at 13:59:42 UTC, SealabJaster wrote:

 large enough and mainstream enough that there are programmers 
 who only know those singular languages to a decent degree.
Yes, and all those really grow out of C++ (except JavaScript that is closer to Self IIRC) both in terms of syntax and semantics. So that is in essence captures what "programming" is to most programmers, I would think.
 Meanwhile there are the more comparatively fringe languages 
 like D, Nim, I guess Rust, and so on, that likely consist of 
 so-called polyglot programmers - those that are proficient in 
 multiple languages.

 It's hard to express my thoughts, but I wonder what affect this 
 has on these fringe languages in general, compared to the more 
 mainstream ones.
That is an interesting perspective. I think D and Nim might have roughly two types of programmers: those that do programming on multiple projects and are polyglot, and those that use the language as a tool in some other process (including hobbyists) and who focus on one language. Then you have those that would want a niche language that is really good at one task, like a very efficient tool for something specific. On the other hand you have those that want one language that covers everything (but then you have to sacrifice being really good at something specific). And that is where niche languages are struggling, for a polyglot programmer it is much easier to defend adopting yet-another-language if it is a very narrow specialty tool (e.g. the best option for DSP, 3D or something like that). Yet polyglot programmers might have much stronger opinions on what features the language lacks also (in comparison to other languages). As a result the process might be a bit self-defeating. The polyglots might push the language to be less attractive for polyglot programmers looking for the best narrow tool for a task. And the non-polyglot programmers don't really have a lot of reason to push back on adding more features that makes the language cover more ground for them (as they haven't seen the consequences in other languages). I think Rust is a bit different. It plays up to "erudite programmers" by giving a sense of being "theory-based" and "academic", and the syntax is reminiscent of more academic languages. I perceive the "marketing surface" of Rust and Haskell to have some common traits, but Rust is easier to deal with for most programmers in a commercial setting. (I am not saying that Rust is academic in nature, only that it is positioned as being more academic than other languages.)
Oct 24 2021
prev sibling next sibling parent reply claptrap <clap trap.com> writes:
On Sunday, 24 October 2021 at 08:42:54 UTC, Ola Fosheim Grøstad 
wrote:
 It us equally puzzeling why prople want "&&" instead of "and" 
 or "||" instead of "or". There is no rational explanation, I 
 think people like to feel that they are using something 
 advanced and that a syntax that that is associated with 
 advanced usage makes them feel more skilled? Kinda like 
 fashion...
Because boolean algebra was already a thing and it was symbolic in nature. So making it wordy would probably seem a bit odd, maybe childish to some people. It'd be like writing arithmetic expressions like this... 1 plus 1 equals 2 If you can understand why people wouldn't want to write arithmetic expressions like that, surely you can understand why some people wouldn't want wordy boolean expressions?
Oct 24 2021
next sibling parent Imperatorn <johan_forsberg_86 hotmail.com> writes:
On Sunday, 24 October 2021 at 10:21:22 UTC, claptrap wrote:
 On Sunday, 24 October 2021 at 08:42:54 UTC, Ola Fosheim Grøstad 
 wrote:
 It us equally puzzeling why prople want "&&" instead of "and" 
 or "||" instead of "or". There is no rational explanation, I 
 think people like to feel that they are using something 
 advanced and that a syntax that that is associated with 
 advanced usage makes them feel more skilled? Kinda like 
 fashion...
Because boolean algebra was already a thing and it was symbolic in nature. So making it wordy would probably seem a bit odd, maybe childish to some people. It'd be like writing arithmetic expressions like this... 1 plus 1 equals 2 If you can understand why people wouldn't want to write arithmetic expressions like that, surely you can understand why some people wouldn't want wordy boolean expressions?
This might be a good reason actually. Coming from logic I at first thought that of course "or" would be ∨ and "and" would be ∧ etc, but then, where are those signs on my keyboard 😭 (I actually have an apl keyboard but that's another thing) So made sense in a way to reuse & and | since they are pretty close as alternative representations, ie ∥ VS || for example.
Oct 24 2021
prev sibling parent reply Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= <ola.fosheim.grostad gmail.com> writes:
On Sunday, 24 October 2021 at 10:21:22 UTC, claptrap wrote:
 Because boolean algebra was already a thing and it was symbolic 
 in nature. So making it wordy would probably seem a bit odd, 
 maybe childish to some people. It'd be like writing arithmetic 
 expressions like this...

 1 plus 1 equals 2

 If you can understand why people wouldn't want to write 
 arithmetic expressions like that, surely you can understand why 
 some people wouldn't want wordy boolean expressions?
I think "not being childish" is a sign of fashion-elitism if it makes code less legible. Many languages that predated C++'s uptake did use more intuitive syntax and had a less noisy appearance. C++ does provide "and" and "or" as keywords though, but people probably don't want to appear as being "not proficient" so I don't actually see it in published code. I have found that using them makes my own code slightly faster to read, so I have recently started to use them. Makes sense to me that "if", "while", "or", "and" ties to flow control, and "&", "|", "+", "/" ties to calculating expressions. I find it slightly easier to read such code when I skim over it (without digging into the specifics). The line noise does of course make programs look more impressive to non-coders: "Whoa, that looks complex, you must be very clever".
Oct 24 2021
parent reply claptrap <clap trap.com> writes:
On Sunday, 24 October 2021 at 14:47:48 UTC, Ola Fosheim Grøstad 
wrote:
 On Sunday, 24 October 2021 at 10:21:22 UTC, claptrap wrote:
 Because boolean algebra was already a thing and it was 
 symbolic in nature. So making it wordy would probably seem a 
 bit odd, maybe childish to some people. It'd be like writing 
 arithmetic expressions like this...

 1 plus 1 equals 2

 If you can understand why people wouldn't want to write 
 arithmetic expressions like that, surely you can understand 
 why some people wouldn't want wordy boolean expressions?
I think "not being childish" is a sign of fashion-elitism if it makes code less legible. Many languages that predated C++'s uptake did use more intuitive syntax and had a less noisy appearance.
I dont think it does make code less legible. I mean the whole point of using symbolic expressions is that they make it easier to express things. It's not fashion, and it's not elitism. If you're writing a ton of boolean expressions over and over using a symbol instead of a word to express a concept will make it easier. It may increase the learning curve for people coming to it fresh, but that doesn't mean that is reason for doing it.
 I have found that using them makes my own code slightly faster 
 to read, so I have recently started to use them.
So you find them slightly faster to read, and anyone who doesn't use them must be showing off?
 Makes sense to me that "if", "while", "or", "and" ties to flow 
 control, and "&", "|", "+", "/" ties to calculating expressions.
But they are not part of control flow, they are part of expressions.
 The line noise does of course make programs look more 
 impressive to non-coders: "Whoa, that looks complex, you must 
 be very clever".
Yeah cause programmers go around showing their code to non coders to try and impress them. In fact it's my number one way to chat up women, show em some over complicated code till they fall swooning into my arms. What are you smoking mate?
Oct 24 2021
parent reply Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= <ola.fosheim.grostad gmail.com> writes:
On Sunday, 24 October 2021 at 20:46:01 UTC, claptrap wrote:
 If you're writing a ton of boolean expressions over and over 
 using a symbol instead of a word to express a concept will make 
 it easier. It may increase the learning curve for people coming 
 to it fresh, but that doesn't mean that is reason for doing it.
The only reason for doing it is that C used it. If there is any difference in typing speed then it would favour letters over symbols.
 So you find them slightly faster to read, and anyone who 
 doesn't use them must be showing off?
No, I made rational argument for why there are no advantages to using "&&" and "||" over "and" and "or". It is entirely cultural.
 But they are not part of control flow, they are part of 
 expressions.
Yes, 99% of them in conditional expressions as selectors in control flow. Why being pedantic?
 Yeah cause programmers go around showing their code to non 
 coders to try and impress them.
No, you don't get the main point. Culture and identity affects preferences and evolution of language, that is a human trait. It is pretty pervasive and well established. There is no reason to assume that programmers are different from other human beings. There is no reason to be offended by this. It should be obvious, I think?
Oct 24 2021
parent reply claptrap <clap trap.com> writes:
On Sunday, 24 October 2021 at 21:26:25 UTC, Ola Fosheim Grøstad 
wrote:
 On Sunday, 24 October 2021 at 20:46:01 UTC, claptrap wrote:
 If you're writing a ton of boolean expressions over and over 
 using a symbol instead of a word to express a concept will 
 make it easier. It may increase the learning curve for people 
 coming to it fresh, but that doesn't mean that is reason for 
 doing it.
The only reason for doing it is that C used it. If there is any difference in typing speed then it would favour letters over symbols.
I'm saying it probably initially came from boolean algebra in maths. Or maybe even electronics, there was a history of boolean logic being expressed with symbols before programming languages even existed. So that's the root. So then you have bitwise operations with symbols because math. Then you need to differentiate between bitwise and boolean logic so && and || makes more sense than using keywords. It's consistent with the already existing bitwise ops.
 So you find them slightly faster to read, and anyone who 
 doesn't use them must be showing off?
No, I made rational argument for why there are no advantages to using "&&" and "||" over "and" and "or". It is entirely cultural.
See above.
 But they are not part of control flow, they are part of 
 expressions.
Yes, 99% of them in conditional expressions as selectors in control flow. Why being pedantic?
if (num % 3) if (ptr == null) Are arithmetic and pointers now control flow? And anything you can put in the brackets after an if or while now becomes control flow? It's not pedantic to call that argument nonsense.
 Yeah cause programmers go around showing their code to non 
 coders to try and impress them.
No, you don't get the main point. Culture and identity affects preferences and evolution of language, that is a human trait. It is pretty pervasive and well established. There is no reason to assume that programmers are different from other human beings.
Programming languages and natural languages have vastly different evolution. People are not subtly changing programming language syntax all the time as a means of self expression. It's designed once and then (for obvious reasons) pretty much stuck that way for ever at least within a given language. And then there's a kind of inertia across languages I think because familiar syntax is seen as a benefit for a new language. I mean how long have && and || been in use? 50 years? That's not evolution and it's not fashion. When someone designs a new programming language I dont think they are asking themselves how can I design the syntax to make themselves look cool, they are either choosing syntax because it is what they are used to, or for some other technical reason. That's the issue I have with what you're saying, I dont think language designers are making syntax choices in order to look cool. In order to suggest that i think you have to have a fundamental misunderstanding of what motivates people to design their own programming language.
Oct 25 2021
next sibling parent reply bauss <jj_1337 live.dk> writes:
On Monday, 25 October 2021 at 10:55:43 UTC, claptrap wrote:
 I'm saying it probably initially came from boolean algebra in 
 maths. Or maybe even electronics, there was a history of 
 boolean logic being expressed with symbols before programming 
 languages even existed.
Math, sure. Electronics, doubt; considering Algorithm for the Analytical Engine was designed in 1883.
Oct 25 2021
parent ClapTrap <clap trap.com> writes:
On Monday, 25 October 2021 at 11:38:16 UTC, bauss wrote:
 On Monday, 25 October 2021 at 10:55:43 UTC, claptrap wrote:
 I'm saying it probably initially came from boolean algebra in 
 maths. Or maybe even electronics, there was a history of 
 boolean logic being expressed with symbols before programming 
 languages even existed.
Math, sure. Electronics, doubt; considering Algorithm for the Analytical Engine was designed in 1883.
What I'm getting at is that whoever designed B, C or whatever came before that probably had a math and or electronics background, so that's why they chose symbolic expressions for bitwise / boolean ops. I doubt Babages engine had any influence on modern programming syntax.
Oct 25 2021
prev sibling parent reply Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= <ola.fosheim.grostad gmail.com> writes:
On Monday, 25 October 2021 at 10:55:43 UTC, claptrap wrote:
 I'm saying it probably initially came from boolean algebra in 
 maths. Or maybe even electronics, there was a history of 
 boolean logic being expressed with symbols before programming 
 languages even existed.
Yes, and that has been evolving as well. Often times they had to make do with what the typograph had available when setting their papers. (Like turning an "A" or "E" upside down.)
 Programming languages and natural languages have vastly 
 different evolution. People are not subtly changing programming 
 language syntax all the time as a means of self expression.
I don't think this is true. Programming language syntax evolve at a higher pace than natural language, and programmers bend the syntax whenever they get a chance to suit their own taste (self expression).
 When someone designs a new programming language I dont think 
 they are asking themselves how can I design the syntax to make 
 themselves look cool, they are either choosing syntax because 
 it is what they are used to, or for some other technical reason.
It is a mix, it is also a strategic choice, making assumptions about what would make it look appealing to existing programmers.
 That's the issue I have with what you're saying, I dont think 
 language designers are making syntax choices in order to look 
 cool.
The designers don't decide which ones of the languages that catch on. What programmers adopt determines the direction of language evolution. There are thousands of programming languages. That is why culture and identity is a force in this evolution process.
Oct 25 2021
parent reply ClapTrap <clap trap.com> writes:
On Monday, 25 October 2021 at 12:22:51 UTC, Ola Fosheim Grøstad 
wrote:
 On Monday, 25 October 2021 at 10:55:43 UTC, claptrap wrote:
 I'm saying it probably initially came from boolean algebra in 
 maths. Or maybe even electronics, there was a history of 
 boolean logic being expressed with symbols before programming 
 languages even existed.
Yes, and that has been evolving as well. Often times they had to make do with what the typograph had available when setting their papers. (Like turning an "A" or "E" upside down.)
Well probably they had their own notation on actual pen and paper. But the fact that when coming to type setting they preferred an upside down 'E' over writing a word makes it look like there is something appealing in writing the expressions symbolically that you just don't seem to grasp.
 Programming languages and natural languages have vastly 
 different evolution. People are not subtly changing 
 programming language syntax all the time as a means of self 
 expression.
I don't think this is true. Programming language syntax evolve at a higher pace than natural language, and programmers bend the syntax whenever they get a chance to suit their own taste (self expression).
They are adding about 1000 new words to the English dictionary each year and many of those are new meanings for existing words. And that's just the stuff that makes it in. Programming languages are not even in the same race. I am constantly having to ask my kids (18 & 22) and their friends what some word or phrase means, (and sometimes I wish I hadn't asked.)
 That's the issue I have with what you're saying, I dont think 
 language designers are making syntax choices in order to look 
 cool.
The designers don't decide which ones of the languages that catch on. What programmers adopt determines the direction of language evolution. There are thousands of programming languages. That is why culture and identity is a force in this evolution process.
Do programmers really think to themselves "I'm not using Pascal because i'll look like a douchebag writing my boolean expressions that way"? I dont see it. I can see people being swayed by language syntax, (I personally dont like overly wordy languages like pascal), but I dont see people making that choice based on what they assume other people will think of them. I mean the only other people who will likely see your code will be people using the same language, so like who cares?
Oct 25 2021
parent reply Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= <ola.fosheim.grostad gmail.com> writes:
On Monday, 25 October 2021 at 22:05:06 UTC, ClapTrap wrote:
 Well probably they had their own notation on actual pen and 
 paper. But the fact that when coming to type setting they 
 preferred an upside down 'E' over writing a word makes it look 
 like there is something appealing in writing the expressions 
 symbolically that you just don't seem to grasp.
Why personal attacks? If you read old math writings you will see that they did actually write out math with plain words. Compact short forms came later and mathematicians still don't agree on one common syntax. So there is indeed a personal aspect to writing mathematics. This become obvious if you read proofs, there are many different styles. Clearly strong personal preferences at display.
 They are adding about 1000 new words to the English dictionary 
 each year and many of those are new meanings for existing words.
That's more like a library. You don't change the grammar when you add new words.
 Programming languages are not even in the same race.
Exactly, they are extended at a far higher pace. 347000 Java repos in the past 2 months. How many new "words" do you think that is?
 I am constantly having to ask my kids (18 & 22) and their 
 friends what some word or phrase means, (and sometimes I wish I 
 hadn't asked.)
Right, and it is a challenge to stay up to date with the constant stream of new versions of programming frameworks.
 Do programmers really think to themselves "I'm not using Pascal 
 because i'll look like a douchebag writing my boolean 
 expressions that way"?
Oh, I think many would shy away from Pascal, Fortran, Ada and other languages that are "old" or "grey beard" without knowing anything about the languages at all!! There is a clear Fashionista element to both programming languages and programming frameworks. Which ties into identity and "being current". Just like there are young wanna-become-programmers that start out with C++ (which is a particularly bad choice) because it is used in AAA-games and they identify themselves as soon to become kickass game-programmers (because that is where their heros/passion are).
Oct 25 2021
next sibling parent Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= <ola.fosheim.grostad gmail.com> writes:
On Monday, 25 October 2021 at 22:24:40 UTC, Ola Fosheim Grøstad 
wrote:
 On Monday, 25 October 2021 at 22:05:06 UTC, ClapTrap wrote:
 Well probably they had their own notation on actual pen and 
 paper. But the fact that when coming to type setting they 
 preferred an upside down 'E' over writing a word makes it look 
 like there is something appealing in writing the expressions 
 symbolically that you just don't seem to grasp.
Why personal attacks? If you read old math writings you will see that they did actually write out math with plain words. Compact short forms came later and mathematicians still don't agree on one common syntax. So there is indeed a personal aspect to writing mathematics. This become obvious if you read proofs, there are many different styles. Clearly strong personal preferences at display.
So, to bring this discussion to an end: I am not saying that people should not use symbols and formalisms. I am saying that using "&&" over "and" is not giving a usability advantage, and I believe that can be both argued and in theory measured (although difficult). If you read mathematical proofs you'll see that proofs that only use formalisms can be very difficult to follow for a human being (although easy to verify for a computer). So written proofs tend to use words where emphasis and understanding is important. When language designers talk about their languages they often emphasis aesthetic dimensions. So language design is just as much art as it is engineering. Which ties to culture, identity and in essence philosophy. Mathematicians talk about beauty in relation to proofs, programmers talk about beauty in relation to coding. Again, influenced by culture and identity. In essence this is a good thing. If language design was all about engineering then we wouldn't have so many options to choose from! :-D
Oct 25 2021
prev sibling parent reply ClapTrap <clap trap.com> writes:
On Monday, 25 October 2021 at 22:24:40 UTC, Ola Fosheim Grøstad 
wrote:
 Why personal attacks? If you read old math writings you will 
 see that they did actually write out math with plain words.
I dont think it is a personal attack to say you dont seem to grasp something.
 Programming languages are not even in the same race.
Exactly, they are extended at a far higher pace. 347000 Java repos in the past 2 months. How many new "words" do you think that is?
If everything written in Java is extending the language, then everything written in English is extending that too. So which is growing faster now?
 I am constantly having to ask my kids (18 & 22) and their 
 friends what some word or phrase means, (and sometimes I wish 
 I hadn't asked.)
Right, and it is a challenge to stay up to date with the constant stream of new versions of programming frameworks.
Or keep up with every book / article / blog post written?
 Do programmers really think to themselves "I'm not using 
 Pascal because i'll look like a douchebag writing my boolean 
 expressions that way"?
Oh, I think many would shy away from Pascal, Fortran, Ada and other languages that are "old" or "grey beard" without knowing anything about the languages at all!! There is a clear Fashionista element to both programming languages and programming frameworks. Which ties into identity and "being current".
I worked with Delphi for about 10 years, i know plenty about it, it was very productive but I wasn't keen on the overly wordy syntax. Fast compile times, strings that just worked, and an amazing IDE were probably the highlights.
 Just like there are young wanna-become-programmers that start 
 out with C++ (which is a particularly bad choice) because it is 
 used in AAA-games and they identify themselves as soon to 
 become kickass game-programmers (because that is where their 
 heros/passion are).
You seem to have a bit of a thing about people who are trying to be cool and fashionable.
Oct 25 2021
parent reply Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= <ola.fosheim.grostad gmail.com> writes:
On Tuesday, 26 October 2021 at 01:06:31 UTC, ClapTrap wrote:
 If everything written in Java is extending the language, then 
 everything written in English is extending that too. So which 
 is growing faster now?
Fair enough, let us say only libraries and frameworks extend the language. :-)
I worked with Delphi for about 10 years, i know plenty about
 it, it was very productive but I wasn't keen on the overly 
 wordy syntax. Fast compile times, strings that just worked, and 
 an amazing IDE were probably the highlights.
Nobody said that everything should be keywords... Have you tried to make everything symbols? I have experimented with unicode syntax in the past few years, and have found that replacing "if" and "while" leads to less legible code, no matter how it is done. And I have tried many options. You can do it if you go fully graphical and leave text editing altogether, but with not with text editing.
 You seem to have a bit of a thing about people who are trying 
 to be cool and fashionable.
Why all the ad hominems? No, I am trying to show you that the dynamic forces include more factors than rational engineering,
Oct 25 2021
parent reply ClapTrap <clap trap.com> writes:
On Tuesday, 26 October 2021 at 04:12:36 UTC, Ola Fosheim Grøstad 
wrote:
 On Tuesday, 26 October 2021 at 01:06:31 UTC, ClapTrap wrote:
 You seem to have a bit of a thing about people who are trying 
 to be cool and fashionable.
Why all the ad hominems? No, I am trying to show you that the dynamic forces include more factors than rational engineering,
Is it ad hominen to point out that you seem to jump to certain explanations of why people do something? Personally i don't think it's relevant, I mean I'm sure it exists, but i dont think kids who wannabee leet programmers drive the adoption of C++. I dont think having "&&" over "and" drives it either.
Oct 26 2021
parent reply Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= <ola.fosheim.grostad gmail.com> writes:
On Tuesday, 26 October 2021 at 09:17:18 UTC, ClapTrap wrote:
 Is it ad hominen to point out that you seem to jump to certain 
 explanations of why people do something?
Yes. You are making assumptions from arbitrary examples. Don't do that.
 Personally i don't think it's relevant, I mean I'm sure it 
 exists, but i dont think kids who wannabee leet programmers 
 drive the adoption of C++.
There is no singular group that keeps C++ relevant. Among those that pick up C++ as a hobby you'll have a rather young audience. It is a language that requires a lot of patience and dedication.
Oct 26 2021
parent reply ClapTrap <clap trap.com> writes:
On Tuesday, 26 October 2021 at 09:33:51 UTC, Ola Fosheim Grøstad 
wrote:
 On Tuesday, 26 October 2021 at 09:17:18 UTC, ClapTrap wrote:
 Is it ad hominen to point out that you seem to jump to certain 
 explanations of why people do something?
Yes. You are making assumptions from arbitrary examples. Don't do that.
When keep using terms like elitist, fashionista, wanabee, to describe people who make choices you disagree with it makes you look like you have a chip on your shoulder. Its not ad hominem to point that out IMO. Labelling whole groups of people with derogatory (implied by context) terms is probably more of an ad hominem (or hominems i guess).
Oct 26 2021
parent reply Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= <ola.fosheim.grostad gmail.com> writes:
On Tuesday, 26 October 2021 at 11:06:55 UTC, ClapTrap wrote:
 When keep using terms like elitist, fashionista, wanabee, to 
 describe people who make choices you disagree with it makes you 
 look like you have a chip on your shoulder.
Good grief. What people? I am making up arbitrary examples describing common traits of most human beings, it describes nobody in particular and everybody in general. I wrote machine language in my teens, not because it was practical, but because I wanted to master the hardware. That is a clear identity motif. There is no reason to be offended by the obvious: humans are strongly affected by culture, identity and emotional aspects. Programmers included.
Oct 26 2021
parent reply ClapTrap <clap trap.com> writes:
On Tuesday, 26 October 2021 at 11:27:50 UTC, Ola Fosheim Grøstad 
wrote:
 On Tuesday, 26 October 2021 at 11:06:55 UTC, ClapTrap wrote:
 When keep using terms like elitist, fashionista, wanabee, to 
 describe people who make choices you disagree with it makes 
 you look like you have a chip on your shoulder.
Good grief. What people? I am making up arbitrary examples describing common traits of most human beings, it describes nobody in particular and everybody in general.
You literally said there's no rational reason to choose "&&" over "and" so those people who do so must be elitist blowhards.
 I wrote machine language in my teens, not because it was 
 practical, but because I wanted to master the hardware. That is 
 a clear identity motif.
Err ok, you did something because you wanted to.
 There is no reason to be offended by the obvious: humans are 
 strongly affected by culture, identity and emotional aspects. 
 Programmers included.
I don't dispute that, what I dispute is that it's relevant when people are choosing tools. People arn't thinking about how cool they will look holding it when they go shopping for a chainsaw, they are thinking about whether it will make the job faster, better or easier. I think the idea that fashion or wanting to appear cool or whatever has anything more than a negligible effect on language adoption is pure BS to be honest.
Oct 26 2021
parent reply Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= <ola.fosheim.grostad gmail.com> writes:
On Tuesday, 26 October 2021 at 21:44:33 UTC, ClapTrap wrote:
 You literally said there's no rational reason to choose "&&" 
 over "and" so those people who do so must be elitist blowhards.
No. Stop making up stuff.
 I don't dispute that, what I dispute is that it's relevant when 
 people are choosing tools. People arn't thinking about how cool 
 they will look holding it when they go shopping for a chainsaw, 
 they are thinking about whether it will make the job faster, 
 better or easier.
Uhm. I most certainly enjoyed how cool my Husqvarna 242G was when I reved it up to 15000 RPM and sliced trunks like butter. I still feel pretty darn cool when I use it, far more so than when using the electric saw. There is plenty of coolness factors in marketing and design of forestry and agriculture equipment. Especially tractors. Just take a look at the visual appearance of modern Valtra and Ferrari tractors.
 I think the idea that fashion or wanting to appear cool or 
 whatever has anything more than a negligible effect on language 
 adoption is pure BS to be honest.
Were you around when C++ and Java lauched commercially? People navigate socially. Hype works. I never mentioned anything about appearance. I mentioned identity and culture. Basically: who do you want to be and which group do feel that you belong to?
Oct 26 2021
parent reply ClapTrap <clap trap.com> writes:
On Tuesday, 26 October 2021 at 22:11:29 UTC, Ola Fosheim Grøstad 
wrote:
 On Tuesday, 26 October 2021 at 21:44:33 UTC, ClapTrap wrote:
 You literally said there's no rational reason to choose "&&" 
 over "and" so those people who do so must be elitist blowhards.
No. Stop making up stuff.
"It us equally puzzeling why prople want "&&" instead of "and" or "||" instead of "or". There is no rational explanation, I think people like to feel that they are using something advanced and that a syntax that that is associated with advanced usage makes them feel more skilled? Kinda like fashion"
 I don't dispute that, what I dispute is that it's relevant 
 when people are choosing tools. People arn't thinking about 
 how cool they will look holding it when they go shopping for a 
 chainsaw, they are thinking about whether it will make the job 
 faster, better or easier.
Uhm. I most certainly enjoyed how cool my Husqvarna 242G was when I reved it up to 15000 RPM and sliced trunks like butter. I still feel pretty darn cool when I use it, far more so than when using the electric saw.
Is that why you bought it? So you can feel cool? I have a bunch of Stihl gear, a Kombi tool, couple of chainsaws. I bought them simply because they are exceptionally good are the job they are designed to do, and they are extremely reliable. Fashion, or thinking how they tie into my ego, didn't factor into the decision to buy them.
 There is plenty of coolness factors in marketing and design of 
 forestry and agriculture equipment. Especially tractors. Just 
 take a look at the visual appearance of modern Valtra and 
 Ferrari tractors.
Farmers will still look at whether the tractor actually has the features they need before considering whether it looks cool or not.
 I think the idea that fashion or wanting to appear cool or 
 whatever has anything more than a negligible effect on 
 language adoption is pure BS to be honest.
Were you around when C++ and Java lauched commercially? People navigate socially. Hype works.
Hype works, but I dont see the hype used used to push programming languages as being of the kind you think it is. It's hype about features, about how it'll make your programs faster, safer, easier. It's not hype plays into peoples ideas about themselves. It's not "Learn Java and be cool", its "Write once run anywhere".
Oct 26 2021
parent reply Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= <ola.fosheim.grostad gmail.con> writes:
On Tuesday, 26 October 2021 at 23:59:34 UTC, ClapTrap wrote:
 On Tuesday, 26 October 2021 at 22:11:29 UTC, Ola Fosheim 
 Grøstad wrote:
 On Tuesday, 26 October 2021 at 21:44:33 UTC, ClapTrap wrote:
 You literally said there's no rational reason to choose "&&" 
 over "and" so those people who do so must be elitist 
 blowhards.
No. Stop making up stuff.
"It us equally puzzeling why prople want "&&" instead of "and" or "||" instead of "or". There is no rational explanation, I think people like to feel that they are using something advanced and that a syntax that that is associated with advanced usage makes them feel more skilled? Kinda like fashion"
Yes, nothing about "elitist blowhard". Why are you obsessing over this point?
 Is that why you bought it? So you can feel cool?
What do you mean? Stihl and Husqvarna are technically comparable, but I prefer Husqvarna, which is nordic and looks and feels better. Basically an identity issue.
 I have a bunch of Stihl gear, a Kombi tool, couple of 
 chainsaws. I bought them simply because they are exceptionally 
 good are the job they are designed to do, and they are 
 extremely reliable.

 Fashion, or thinking how they tie into my ego, didn't factor 
 into the decision to buy them.
Nobody thinks about identity issues, but they are there for sure. How can you know that one tool is better than any other tool, or what is good enough? You dont know until it breaks. So you navigate by some external source. You cannot learn all languages and make a rational choice, you have to make a choice based on some limited information. Or go with what you are used to or comfortable with (ties into identity).
 It's not hype plays into peoples ideas about themselves. It's 
 not "Learn Java and be cool", its "Write once run anywhere".
I dont agree. Programmers often put more emphasis on performance than is rational for the software they are going to write. That ties into identity. Same thing with cars, when people feel that they need a more powerful engine or faster car than you can make good use of in a city. People like to feel empowered beyond what they need. End users want the full edition of software even when the lite edition covers their needs and is less confusing to use. I would prefer the pro line Husqvarna saw even though the hobby saw works just as well, meaning I might pay double price for getting a heated handle that has a more sturdy feel. That makes me feel ready for professional work, which is a good feeling. What makes us feel empowered isnt entirely rational, but that feeling is something we seek. I am fully aware that PhP is sufficient for webwork, but I don't feel empowered when using it. It does not feel like a professional tool, and that has a lot to do with syntax. From a rational point of view, you might argue that PhP is just as good as any other tool. But it does not fit with my identity.
Oct 26 2021
parent reply ClapTrap <clap trap.com> writes:
On Wednesday, 27 October 2021 at 01:05:22 UTC, Ola Fosheim 
Grøstad wrote:
 On Tuesday, 26 October 2021 at 23:59:34 UTC, ClapTrap wrote:
 On Tuesday, 26 October 2021 at 22:11:29 UTC, Ola Fosheim 
 Grøstad wrote:

 Is that why you bought it? So you can feel cool?
What do you mean? Stihl and Husqvarna are technically comparable, but I prefer Husqvarna, which is nordic and looks and feels better. Basically an identity issue.
Exactly!! If they are technically comparable then you would choose the one that looks more nordic. If this identity nonsense comes in it only does so after technical requirements are met. And chainsaws are pretty simple machines, I mean in terms of design they are pretty much all at the same place. So you can probably find very similarly specced machines by all the big manufacturers. Programming languages are not like that, they're not technically comparable, you pick any two languages you can find a shed load of technical reasons to chose one over the other.
 Fashion, or thinking how they tie into my ego, didn't factor 
 into the decision to buy them.
Nobody thinks about identity issues, but they are there for sure. How can you know that one tool is better than any other tool, or what is good enough? You dont know until it breaks. So you navigate by some external source.
You read up on the web, or you ask someone you think will be able to help. But you don't go and ask them "I need a chainsaw, which is the most nordic?". Or maybe you do? :)
 It's not hype plays into peoples ideas about themselves. It's 
 not "Learn Java and be cool", its "Write once run anywhere".
I am fully aware that PhP is sufficient for webwork, but I don't feel empowered when using it. It does not feel like a professional tool, and that has a lot to do with syntax. From a rational point of view, you might argue that PhP is just as good as any other tool. But it does not fit with my identity.
Saying PhP is just as good as any other tool is not a rational point of view. And if you use statements like that in your reasoning then you end up in stupid places where you cant dislike like something just because it's crap. It has to be because it doesn't fit your identity.
Oct 27 2021
parent Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= <ola.fosheim.grostad gmail.com> writes:
On Wednesday, 27 October 2021 at 21:31:05 UTC, ClapTrap wrote:
 And chainsaws are pretty simple machines, I mean in terms of 
 design they are pretty much all at the same place. So you can 
 probably find very similarly specced machines by all the big 
 manufacturers.
Hm, I don't think anyone are making high speed chainsaws anymore (I think they max out at 11000RPM now). Only matters slightly when delimbing really. RPM goes down real fast when you enter anything with thickness (it is a thinning saw, so not very powerful, but easy handling).
 Programming languages are not like that, they're not 
 technically comparable, you pick any two languages you can find 
 a shed load of technical reasons to chose one over the other.
Most people tend to go with what-other-people-are-going-with. For instance, C++ is pretty much a lonely king-on-the-hill for graphics and audio. You go with the group that you identify with is using. Java for business applications. And so on. I don't actually think average developers look for new opportunities when picking a language. When they pick a framework, they might. For language choice, I think average programmers go with something that makes them feel safe.
 You read up on the web, or you ask someone you think will be 
 able to help. But you don't go and ask them "I need a chainsaw, 
 which is the most nordic?".

 Or maybe you do? :)
Heh, when I was young I totally wanted the Jonsered 20xx TURBO. That "TURBO" made it seem totally awesome (but probably was no better, clever marketing ;^). All the pro saws in stores were either Husqvarna or Jonsered back then (Swedish brands) IIRC. I doubt I would have considered any other brands, just assumed other brands were crap. And I still feel/assume that Husqvarna is better than Stihl in handling and build quality, and would not consider other brands than those two. Taking down windfalls can be dangerous, I don't want the saw to fail on me. As I said, you don't know if a tool is robust until it fails.
 Saying PhP is just as good as any other tool is not a rational 
 point of view.
The syntax isn't great, but the semantics in "modern" Php is good enough. I personally don't feel the package is up to a professional standard, although people obviously use it in a pro setting. So it is a feeling, more than a dissection. If I am going to spend a lot of time focusing on a language I want an aesthetics I like, so that I can write code I from time-to-time feel is beautiful. Can you be truly satisfied with a language if you don't like the looks of the code at the end of the day? I doubt it, but then we are in a very subjective landscape! It is kinda like why I want the pro line Husqvarna, I want the top handle to be in metal. It gives me a better feeling and I can focus more on the work (and forget about the tool). It is kinda subjective though, whether one feels a metal handle is better than a plastic handle.
Oct 27 2021
prev sibling parent reply Guillaume Piolat <first.last gmail.com> writes:
On Sunday, 24 October 2021 at 08:42:54 UTC, Ola Fosheim Grøstad 
wrote:
 It us equally puzzeling why prople want "&&" instead of "and" 
 or "||" instead of "or". There is no rational explanation, I 
 think people like to feel that they are using something 
 advanced and that a syntax that that is associated with 
 advanced usage makes them feel more skilled? Kinda like 
 fashion...
Like genetic random drift, those boolean operators are mostly because C won over Pascal. The boolean operators in Pascal and Ada are more readable in my opinion. So I guess the majority of people in the native just never experienced those other operators.
Oct 25 2021
parent reply ClapTrap <clap trap.com> writes:
On Monday, 25 October 2021 at 10:01:35 UTC, Guillaume Piolat 
wrote:
 On Sunday, 24 October 2021 at 08:42:54 UTC, Ola Fosheim Grøstad 
 wrote:
 It us equally puzzeling why prople want "&&" instead of "and" 
 or "||" instead of "or". There is no rational explanation, I 
 think people like to feel that they are using something 
 advanced and that a syntax that that is associated with 
 advanced usage makes them feel more skilled? Kinda like 
 fashion...
Like genetic random drift, those boolean operators are mostly because C won over Pascal. The boolean operators in Pascal and Ada are more readable in my opinion. So I guess the majority of people in the native just never experienced those other operators.
Pascal has shr, shl, begin, end, maybe other wordy stuff, where do you draw the line? Or rather where do you write "line"? :)
Oct 25 2021
next sibling parent reply Guillaume Piolat <first.last gmail.com> writes:
On Monday, 25 October 2021 at 12:00:09 UTC, ClapTrap wrote:
 Pascal has shr, shl, begin, end, maybe other wordy stuff, where 
 do you draw the line? Or rather where do you write "line"? :)
baby vs bathwater
Oct 25 2021
parent reply ClapTrap <clap trap.com> writes:
On Monday, 25 October 2021 at 13:23:57 UTC, Guillaume Piolat 
wrote:
 On Monday, 25 October 2021 at 12:00:09 UTC, ClapTrap wrote:
 Pascal has shr, shl, begin, end, maybe other wordy stuff, 
 where do you draw the line? Or rather where do you write 
 "line"? :)
baby vs bathwater
I know the idiom but I dont understand what you mean in this context.
Oct 25 2021
parent Guillaume Piolat <first.last gmail.com> writes:
On Monday, 25 October 2021 at 22:06:25 UTC, ClapTrap wrote:
 On Monday, 25 October 2021 at 13:23:57 UTC, Guillaume Piolat 
 wrote:
 On Monday, 25 October 2021 at 12:00:09 UTC, ClapTrap wrote:
 Pascal has shr, shl, begin, end, maybe other wordy stuff, 
 where do you draw the line? Or rather where do you write 
 "line"? :)
baby vs bathwater
I know the idiom but I dont understand what you mean in this context.
Er sorry. I was just meaning that Pascal did have good ideas that have suffered from its demise.
Oct 26 2021
prev sibling parent reply Basile B. <b2.temp gmx.com> writes:
On Monday, 25 October 2021 at 12:00:09 UTC, ClapTrap wrote:
 Pascal has shr, shl, begin, end, maybe other wordy stuff, where 
 do you draw the line? Or rather where do you write "line"? :)
The line is simply the style consistency. - `and` and `or` are named operators - `&&` and `||` are symbolic operators Named operators cause problems for the sustainability of a language over time. A language should be consistent, so when new operators have to be added, pascal-like languages must stick to the tradition. A few years back there was a discussion on the freepascal forums about [the conditional expressions](https://www.mail-archive.com/fpc-pascal lists.freepascal org/msg41242.html). To keep the language coherant (i.e dont start to use _symbolic operators_) the final proposition was an intrinsic `IfThen`. It's easier to create new operators if the _symbolic_ style is used. To go back to `&&` and `||`... There are just the shortcut versions of `&` and `|` ... Pascal can use `and` and `or` for both logical and bitwise arithmetic expressions for the sole and unique reason that **there is no implicit conversion** from `Boolean` to the integer types and and no implicit boolean evalation of integer types. So... in `if e1 and e2 then ...`, to compile `and` has to be a shortcut logical and. dot. (`e3 := e1 and e2; if e3 then...` is not rewritten `if e3 <> 0 then...`.) You see that finally this has nothing to do with the hype or whatever. In both case the style and the semantic are perfectly coherant.
Oct 26 2021
parent reply Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= <ola.fosheim.grostad gmail.com> writes:
On Wednesday, 27 October 2021 at 01:18:47 UTC, Basile B. wrote:
 You see that finally this has nothing to do with the hype or 
 whatever. In both case the style and the semantic are perfectly 
 coherant.
No, to be consistent with other infix operators for integers +*/- you would use symbols for bit manipulation. If you resuse integer operators for booleans, then conditional expressions get more difficult to read when they contain both. Which is bad for usability. Side note: Simula had or, or else, and, and then. So, both with and without short circuit.
Oct 26 2021
parent reply Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= <ola.fosheim.grostad gmail.com> writes:
On Wednesday, 27 October 2021 at 06:58:13 UTC, Ola Fosheim 
Grøstad wrote:
 Side note: Simula had or, or else, and, and then. So, both with 
 and without short circuit.
Please note that the original Pascal did not have bit operations IIRC. The p-code machine had only 5 math operators. It was a simplified expression of ideas from Algol.
Oct 27 2021
parent reply Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= <ola.fosheim.grostad gmail.com> writes:
FWIW, from Stefik and Sibert, «An Empirical Investigation into 
Programming Language syntax», _ACM Transactions on Computing 
Education_, vol. 13, No. 2, 2013:

Both programmers and non-programmers had their preference for 
*boolean and* ordered as: x and y, x&y, x&&y. With a dip in 
interest for the && version. Which isn't surprising.

For *boolean or* there was more deviance. Non-programmers 
preferred: x or y, either x or y, x and y (!). Non-programmers 
seemed to have problem grasping the concept of logical or. 
Programmers preferred: x or y, either x or y, x||y.

For *string concatenation* programmers had a preference for: +, 
&, _ and a dislike for: -, ?, $

(The authors list many other constructs.)
Oct 27 2021
next sibling parent reply Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= <ola.fosheim.grostad gmail.com> writes:
On Wednesday, 27 October 2021 at 14:07:42 UTC, Ola Fosheim 
Grøstad wrote:
 FWIW, from Stefik and Sibert, «An Empirical Investigation into 
 Programming Language syntax», _ACM Transactions on Computing 
 Education_, vol. 13, No. 2, 2013:
Another paper, Altadmri and Brown, «37 Million Compilations: Investigating Novice Programming Mistakes in LargeScale Student Data», *SIGCSE’15*. They point out that using "&" instead of "&&" is a mistake that it takes a long time to fix since it does not lead to a compilation error. It occured a bit more often than having a mismatch between a function return type and the type of the variable it assigns to.
Oct 27 2021
parent reply Basile B. <b2.temp gmx.com> writes:
On Wednesday, 27 October 2021 at 16:54:07 UTC, Ola Fosheim 
Grøstad wrote:
 On Wednesday, 27 October 2021 at 14:07:42 UTC, Ola Fosheim 
 Grøstad wrote:
 FWIW, from Stefik and Sibert, «An Empirical Investigation into 
 Programming Language syntax», _ACM Transactions on Computing 
 Education_, vol. 13, No. 2, 2013:
Another paper, Altadmri and Brown, «37 Million Compilations: Investigating Novice Programming Mistakes in LargeScale Student Data», *SIGCSE’15*. They point out that using "&" instead of "&&" is a mistake that it takes a long time to fix since it does not lead to a compilation error. It occured a bit more often than having a mismatch between a function return type and the type of the variable it assigns to.
I'm a bit surprised by the results of these studies. I'd say that what people prefer actually does not matter because they dont necessarily have in mind the consistency criterion mentioned earlier. (side note: there's actually a proglang, Quorum, that has part of the design bassed on surveys !) What's important is that the compiler should prevent reasoning errors, just like when AssignExp is rejected if used as condition.
Oct 27 2021
parent reply Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= <ola.fosheim.grostad gmail.com> writes:
On Wednesday, 27 October 2021 at 17:41:40 UTC, Basile B. wrote:
 I'm a bit surprised by the results of these studies. I'd say 
 that what people prefer actually does not matter because they 
 dont necessarily have in mind the consistency criterion 
 mentioned earlier.
My phrasing may have been a bit imprecise. The students were asked to rank the phrases as to how well they thought they matched up to the concept. So, basically, how intuitive they found them. They had C++ experience.
 (side note: there's actually a proglang, Quorum, that has part 
 of the design bassed on surveys !)
Yes, I found some papers on that one too! It appears to have been developed for blind programmers (?!), but has been adopted more widely in teaching. I also found a paper that created and played melodies when debugging programs so that you could hear how the program executed. I assume this means that you could hear when a loop was exited, a branch was taken etc. Surprising things to be found when looking around! Unfortunately there has been very few controlled usability studies of programming language designs... I found a presentation that claimed there has only been 22 studies (over 50 years?).
 What's important is that the compiler should prevent reasoning 
 errors, just like when AssignExp is rejected if used as 
 condition.
I think there are many aspects to focus on. I'll keep it short here. Some dimensions I think are relevant: * learnability: how intuitive and natural is the syntax? * retention: how easy is it to remember what you have learned (consistency, mnemonics etc)? * skimmable: how good impression of what goes on do you get by skim-reading? * legibility: how quickly do you get a correct understanding of what goes on when reading? * error prevention: is the syntax resistant to typos that go undetected? Clearly "and"/"or" is more resistant to typos than "&&"/"||", and also more skimmable with high learnability/retention (especially for "or"). But, if you don't allow implicit conversion to/from bool then the compilation stage should catch most such typos in the type system. So the impact of syntax also depends on language semantics.
Oct 27 2021
next sibling parent Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= <ola.fosheim.grostad gmail.com> writes:
On Wednesday, 27 October 2021 at 18:35:24 UTC, Ola Fosheim 
Grøstad wrote:
 On Wednesday, 27 October 2021 at 17:41:40 UTC, Basile B. wrote:
 I'm a bit surprised by the results of these studies. I'd say 
 that what people prefer actually does not matter because they 
 dont necessarily have in mind the consistency criterion 
 mentioned earlier.
My phrasing may have been a bit imprecise. The students were asked to rank the phrases as to how well they thought they matched up to the concept. So, basically, how intuitive they found them. They had C++ experience.
May also add that the number of years they had used C++ did affect how well they thought the C++ phrases matched the concepts, as we might expect.
Oct 27 2021
prev sibling parent reply Basile B. <b2.temp gmx.com> writes:
On Wednesday, 27 October 2021 at 18:35:24 UTC, Ola Fosheim 
Grøstad wrote:
 On Wednesday, 27 October 2021 at 17:41:40 UTC, Basile B. wrote:
 [...]
 But, if you don't allow implicit conversion to/from bool then 
 the compilation stage should catch most such typos in the type 
 system. So the impact of syntax also depends on language 
 semantics.
Yeah, that's a point of agreement.
Oct 28 2021
parent reply Basile B. <b2.temp gmx.com> writes:
On Thursday, 28 October 2021 at 10:34:28 UTC, Basile B. wrote:
 On Wednesday, 27 October 2021 at 18:35:24 UTC, Ola Fosheim 
 Grøstad wrote:
 On Wednesday, 27 October 2021 at 17:41:40 UTC, Basile B. wrote:
 [...]
 But, if you don't allow implicit conversion to/from bool then 
 the compilation stage should catch most such typos in the type 
 system. So the impact of syntax also depends on language 
 semantics.
Yeah, that's a point of agreement.
BTW "to bool", as you saiy, is **not an implicit conv**... it's more a special case that **only** happens when a condition is evaluated so `if` condition, `while` condition, CondExp condition, AssertExp, and I think that's all. That detail is important to understand why pascal `and` works perfectly with both numbers and booleans ;)
Oct 28 2021
parent Basile B. <b2.temp gmx.com> writes:
On Thursday, 28 October 2021 at 10:41:23 UTC, Basile B. wrote:
 On Thursday, 28 October 2021 at 10:34:28 UTC, Basile B. wrote:
 On Wednesday, 27 October 2021 at 18:35:24 UTC, Ola Fosheim 
 Grøstad wrote:
 On Wednesday, 27 October 2021 at 17:41:40 UTC, Basile B. 
 wrote:
 [...]
 But, if you don't allow implicit conversion to/from bool then 
 the compilation stage should catch most such typos in the 
 type system. So the impact of syntax also depends on language 
 semantics.
Yeah, that's a point of agreement.
BTW "to bool", as you saiy, is **not an implicit conv**... it's more a special case that **only** happens when a condition is evaluated so `if` condition, `while` condition, CondExp condition, AssertExp, and I think that's all. That detail is important to understand why pascal `and` works perfectly with both numbers and booleans ;)
it's because it does not do that. If it does, then `and` is directly broken.
Oct 28 2021
prev sibling parent reply Dom DiSc <dominikus scherkl.de> writes:
On Wednesday, 27 October 2021 at 14:07:42 UTC, Ola Fosheim 
Grøstad wrote:
 FWIW, from Stefik and Sibert, «An Empirical Investigation into 
 Programming Language syntax», _ACM Transactions on Computing 
 Education_, vol. 13, No. 2, 2013:

 Both programmers and non-programmers had their preference for 
 *boolean and* ordered as: x and y, x&y, x&&y. With a dip in 
 interest for the && version. Which isn't surprising.

 For *boolean or* there was more deviance. Non-programmers 
 preferred: x or y, either x or y, x and y (!). Non-programmers 
 seemed to have problem grasping the concept of logical or. 
 Programmers preferred: x or y, either x or y, x||y.

 For *string concatenation* programmers had a preference for: +, 
 &, _ and a dislike for: -, ?, $
As with all statistics the answers are heavily biased by the choices that were not asked for: I would strongly prefer ∨ for or, ∧ for and (and ⊻ for exclusive or btw) and I think ~ for cat is a good choice (and far better than +), but I would prefer ∘.
Oct 28 2021
parent reply Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= <ola.fosheim.grostad gmail.com> writes:
On Thursday, 28 October 2021 at 07:05:47 UTC, Dom DiSc wrote:
 I would strongly prefer ∨ for or, ∧ for and (and ⊻ for 
 exclusive or btw) and I think ~ for cat is a good choice (and 
 far better than +), but I would prefer ∘.
"v" was available, but I don't think they got unicode alternatives.
Oct 28 2021
parent reply jfondren <julian.fondren gmail.com> writes:
On Thursday, 28 October 2021 at 07:17:00 UTC, Ola Fosheim Grøstad 
wrote:
 On Thursday, 28 October 2021 at 07:05:47 UTC, Dom DiSc wrote:
 I would strongly prefer ∨ for or, ∧ for and (and ⊻ for 
 exclusive or btw) and I think ~ for cat is a good choice (and 
 far better than +), but I would prefer ∘.
"v" was available, but I don't think they got unicode alternatives.
https://tryapl.org/ uni: ∨∧ asc: v^
Oct 28 2021
next sibling parent Dom DiSc <dominikus scherkl.de> writes:
On Thursday, 28 October 2021 at 07:45:38 UTC, jfondren wrote:
 https://tryapl.org/

 uni: ∨∧
 asc: v^
Only that ^ atm is used as xor, not and :-( (uh, writing such a sentence makes very clear, why using words instead of symbolic operators is such a bad idea)
Oct 28 2021
prev sibling next sibling parent reply Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= <ola.fosheim.grostad gmail.com> writes:
On Thursday, 28 October 2021 at 07:45:38 UTC, jfondren wrote:
 https://tryapl.org/

 uni: ∨∧
 asc: v^
I think you would have to write to the authors to find out all the alternatives they gave. I don't know if they provided "^" or not.
Oct 28 2021
parent Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= <ola.fosheim.grostad gmail.com> writes:
On Thursday, 28 October 2021 at 08:54:35 UTC, Ola Fosheim Grøstad 
wrote:
 On Thursday, 28 October 2021 at 07:45:38 UTC, jfondren wrote:
 https://tryapl.org/

 uni: ∨∧
 asc: v^
I think you would have to write to the authors to find out all the alternatives they gave. I don't know if they provided "^" or not.
Ok, so I read the article again and they did and they were ranked low for OR: The three lowest ranked for non-programmers: "v", "^", "nor" The three lowest ranked for programmers: "^", "exclusive and", "nor" I don't know how they were ranked for AND.
Oct 28 2021
prev sibling parent Abdulhaq <alynch4047 gmail.com> writes:
On Thursday, 28 October 2021 at 07:45:38 UTC, jfondren wrote:
 On Thursday, 28 October 2021 at 07:17:00 UTC, Ola Fosheim 
 Grøstad wrote:
 On Thursday, 28 October 2021 at 07:05:47 UTC, Dom DiSc wrote:
 I would strongly prefer ∨ for or, ∧ for and (and ⊻ for 
 exclusive or btw) and I think ~ for cat is a good choice (and 
 far better than +), but I would prefer ∘.
"v" was available, but I don't think they got unicode alternatives.
https://tryapl.org/ uni: ∨∧ asc: v^
In case anyone is unfamiliar with it, Notation As A Tool Of Thought (Iverson) https://www.jsoftware.com/papers/tot.htm
Oct 28 2021
prev sibling next sibling parent Guillaume Piolat <first.last gmail.com> writes:
On Monday, 11 October 2021 at 15:59:10 UTC, Atila Neves wrote:
 * Features you'd like to see in D
2 - A BetterC mode but with classes, exceptions, and no GC. 3 - ProtoObject. A nogc nothrow .destroy. 4 - Progressive runtime replaces BetterC. It becomes entirely static and magically works in shared objects. 5 - impure
Oct 11 2021
prev sibling next sibling parent reply Adam D Ruppe <destructionator gmail.com> writes:
On Monday, 11 October 2021 at 15:59:10 UTC, Atila Neves wrote:
 * Worst features implemented in a non-toy language
Well not a feature per se, but the idea that number of keywords or number of features really matters. People argue you should remove things just to remove things. But this often just moves the inherent difficulty of programming from the language to the code. You don't wanna go too far with it, of course, but there is simple metric here.
 * Worst features (in your opinion) in D
The whole int promotion and casting mess. Two ideas that sound fine in isolation but make things just nearly unusable in real life when combined.
 * Features you'd like to see in D
Explicit implicit construction. Minimally on return values, but also on function arguments would be nice. Note the constructor called implicitly must be explicitly labeled implicit.
Oct 11 2021
next sibling parent Adam D Ruppe <destructionator gmail.com> writes:
On Monday, 11 October 2021 at 20:51:13 UTC, Adam D Ruppe wrote:
 You don't wanna go too far with it, of course, but there is 
 simple metric here.
err there is NO simple metric here.
Oct 11 2021
prev sibling parent Dr Machine Code <jckj33 gmail.com> writes:
On Monday, 11 October 2021 at 20:51:13 UTC, Adam D Ruppe wrote:
 On Monday, 11 October 2021 at 15:59:10 UTC, Atila Neves wrote:
 [...]
Well not a feature per se, but the idea that number of keywords or number of features really matters. People argue you should remove things just to remove things. But this often just moves the inherent difficulty of programming from the language to the code. You don't wanna go too far with it, of course, but there is simple metric here.
 [...]
The whole int promotion and casting mess. Two ideas that sound fine in isolation but make things just nearly unusable in real life when combined.
 [...]
Explicit implicit construction. Minimally on return values, but also on function arguments would be nice. Note the constructor called implicitly must be explicitly labeled implicit.
could you give an example on how those features would be like?
Nov 14 2021
prev sibling next sibling parent reply RazvanN <razvan.nitu1305 gmail.com> writes:
On Monday, 11 October 2021 at 15:59:10 UTC, Atila Neves wrote:
 I'm brainstorming about what I'll talk about at DConf, and 
 during a conversation with Walter I thought it might be cool to 
 talk about:

 * Worst features implemented in a non-toy language
 * Worst features (in your opinion) in D
 * Features you'd like to see in D

 Ideas? Examples?

 Thanks!
Worst features: - ability to define alias this on class objects - inout
Oct 11 2021
parent reply 12345swordy <alexanderheistermann gmail.com> writes:
On Monday, 11 October 2021 at 21:22:29 UTC, RazvanN wrote:
 On Monday, 11 October 2021 at 15:59:10 UTC, Atila Neves wrote:
 I'm brainstorming about what I'll talk about at DConf, and 
 during a conversation with Walter I thought it might be cool 
 to talk about:

 * Worst features implemented in a non-toy language
 * Worst features (in your opinion) in D
 * Features you'd like to see in D

 Ideas? Examples?

 Thanks!
Worst features: - ability to define alias this on class objects
Yes! This right here is the worst feature as it is a source of headaches when it comes to compiler bugs. We can replace this that introduce new features for the classes such as the much needed properties overhaul that is still WIP. https://github.com/12345swordy/DIPs/blob/properties/DIPs/%40get%20%40set%20.md and introduce default interface implementation. Before you ask, No, using string mixin or templates for implementing interfaces is NOT considered to be a default interface implementation. See here: https://github.com/dotnet/csharplang/blob/main/proposals/csharp-8.0/default-interface-methods.md - Alex
Oct 11 2021
parent reply jmh530 <john.michael.hall gmail.com> writes:
On Monday, 11 October 2021 at 21:32:52 UTC, 12345swordy wrote:
 [snip]
 Before you ask, No, using string mixin or templates for 
 implementing interfaces  is NOT considered to be a default 
 interface implementation.
 See here: 
 https://github.com/dotnet/csharplang/blob/main/proposals/csharp-8.0/default-interface-methods.md


 - Alex
Interfaces can have final methods, you just can't overwrite them.
Oct 11 2021
parent reply 12345swordy <alexanderheistermann gmail.com> writes:
On Monday, 11 October 2021 at 21:40:08 UTC, jmh530 wrote:
 On Monday, 11 October 2021 at 21:32:52 UTC, 12345swordy wrote:
 [snip]
 Before you ask, No, using string mixin or templates for 
 implementing interfaces  is NOT considered to be a default 
 interface implementation.
 See here: 
 https://github.com/dotnet/csharplang/blob/main/proposals/csharp-8.0/default-interface-methods.md


 - Alex
Interfaces can have final methods, you just can't overwrite them.
Did you not read the file that I linked? - Alex
Oct 11 2021
parent jmh530 <john.michael.hall gmail.com> writes:
On Monday, 11 October 2021 at 21:54:05 UTC, 12345swordy wrote:
 [snip]
 Interfaces can have final methods, you just can't overwrite 
 them.
Did you not read the file that I linked? - Alex
I skimmed it.
Oct 11 2021
prev sibling next sibling parent reply monkyyy <crazymonkyyy gmail.com> writes:
 * Worst features implemented in a non-toy language
* Embedding js in an html document. * adding objects to an existing language
 * Worst features (in your opinion) in D
* nontrivial namespace collisions when importing std * int promotion * verbose enums * contracts and all the cute ideas expanding a template header to affect the matching * sword of damocles of safe by default or who knows what koolaid being enabled one day
 * Features you'd like to see in D
* base types having fake opoverloads ( 2.opCmp(3) == 1) * universal function call syntax being universal (let me define a function in the same scope that I ufcs it) * a nice overload for _____TrAiTs(compiles,mixin("foo.bar"))
Oct 11 2021
next sibling parent reply jfondren <julian.fondren gmail.com> writes:
On Monday, 11 October 2021 at 21:41:45 UTC, monkyyy wrote:
 * nontrivial namespace collisions when importing std
Are these still around? This compiles now: ```d unittest { import std; assert(!std.ascii.isAlpha('5')); } unittest { import std; import std.ascii : isAlpha; assert(isAlpha('X')); assert(std.uni.isAlpha('X')); } ```
Oct 11 2021
parent monkyyy <crazymonkyyy gmail.com> writes:
On Tuesday, 12 October 2021 at 00:13:45 UTC, jfondren wrote:
 On Monday, 11 October 2021 at 21:41:45 UTC, monkyyy wrote:
 * nontrivial namespace collisions when importing std
Are these still around? This compiles now: ```d unittest { import std; assert(!std.ascii.isAlpha('5')); } unittest { import std; import std.ascii : isAlpha; assert(isAlpha('X')); assert(std.uni.isAlpha('X')); } ```
The one that annoyed me was stdio and file, write
Oct 12 2021
prev sibling parent reply Atila Neves <atila.neves gmail.com> writes:
On Monday, 11 October 2021 at 21:41:45 UTC, monkyyy wrote:
 * Worst features implemented in a non-toy language
* Embedding js in an html document. * adding objects to an existing language
 * Worst features (in your opinion) in D
* nontrivial namespace collisions when importing std * int promotion * verbose enums * contracts and all the cute ideas expanding a template header to affect the matching * sword of damocles of safe by default or who knows what koolaid being enabled one day
Interesting. What is it about safe by default that would worry you?
Oct 14 2021
next sibling parent reply Paul Backus <snarwin gmail.com> writes:
On Thursday, 14 October 2021 at 16:48:12 UTC, Atila Neves wrote:
 On Monday, 11 October 2021 at 21:41:45 UTC, monkyyy wrote:
 * sword of damocles of safe by default or who knows what 
 koolaid being enabled one day
Interesting. What is it about safe by default that would worry you?
I've interacted with monkyyy a bunch in the community Discord. He's the kind of programmer who would rather write code with undefined behavior and get away with it than follow any kind of compiler-enforced rules. Most programmers with this attitude eventually get it beaten out of them by painful experience. I wouldn't put too much stock in it.
Oct 14 2021
parent jfondren <julian.fondren gmail.com> writes:
On Thursday, 14 October 2021 at 17:02:49 UTC, Paul Backus wrote:
 On Thursday, 14 October 2021 at 16:48:12 UTC, Atila Neves wrote:
 On Monday, 11 October 2021 at 21:41:45 UTC, monkyyy wrote:
 * sword of damocles of safe by default or who knows what 
 koolaid being enabled one day
Interesting. What is it about safe by default that would worry you?
I've interacted with monkyyy a bunch in the community Discord. He's the kind of programmer who would rather write code with undefined behavior and get away with it than follow any kind of compiler-enforced rules. Most programmers with this attitude eventually get it beaten out of them by painful experience. I wouldn't put too much stock in it.
The emphasis there should be on "sword of damocles" (uncertainty wrt. a future negative outcome) and "being enabled one day" (a change in the language). d is currently system by default, and making it safe by default is a breaking change that requires people to run through their code and change it, even if just to add a system: at the top. If you personally greatly value a breaking change then maybe you won't mind this kind of maintenance, but others it's imposed bitrot. dub could be in the position of automatically trying --revert= flags if the latest tag release is older than some breaking change to dmd
Oct 14 2021
prev sibling parent monkyyy <crazymonkyyy gmail.com> writes:
On Thursday, 14 October 2021 at 16:48:12 UTC, Atila Neves wrote:
 On Monday, 11 October 2021 at 21:41:45 UTC, monkyyy wrote:
 * Worst features implemented in a non-toy language
* Embedding js in an html document. * adding objects to an existing language
 * Worst features (in your opinion) in D
* nontrivial namespace collisions when importing std * int promotion * verbose enums * contracts and all the cute ideas expanding a template header to affect the matching * sword of damocles of safe by default or who knows what koolaid being enabled one day
Interesting. What is it about safe by default that would worry you?
verbosity
Oct 30 2021
prev sibling next sibling parent apz28 <home home.com> writes:
On Monday, 11 October 2021 at 15:59:10 UTC, Atila Neves wrote:
 I'm brainstorming about what I'll talk about at DConf, and 
 during a conversation with Walter I thought it might be cool to 
 talk about:

 * Worst features (in your opinion) in D
Attribute soup 1. inconsistent - some with leading ' ' & some without all attributes should start with . This will help to reduce number of key/reserved words 2. need re-declare attributes for aggregated types (struct/class) even if it is already declared on module level 3. All attributes should be non-negative word and introduce negation Ex: gc: nogc become !gc Simple example module x; !gc !throw: void funcionDoNotThrow() {} // Reverse the above module attribute setting void functionThrow() throw {}
Oct 11 2021
prev sibling next sibling parent reply max haughton <maxhaton gmail.com> writes:
On Monday, 11 October 2021 at 15:59:10 UTC, Atila Neves wrote:
 I'm brainstorming about what I'll talk about at DConf, and 
 during a conversation with Walter I thought it might be cool to 
 talk about:

 * Worst features implemented in a non-toy language
 * Worst features (in your opinion) in D
 * Features you'd like to see in D

 Ideas? Examples?

 Thanks!
__traits should've died years ago. Its continued existence shows some level of paralysis. The decision to build languages as monolithic lumps of specification, then a compiler, also phased in it's design, while simple, I think will be a detriment in the post Moore's law age, as it makes it very irritating to use and understand the full muscle of the optimizer *in the right places* - and fundamentally limits the potential of the/a language in a now post-heterogenous world: you should he able to compile for a GPU as part of the compiler a la a trait (This is an acceptable use of the keyword, reflection is not). I think D's worst feature is really a human tendency to avoid language solutions for things. sumtype is a good library, but it should be core language for example. Typecons.tuple is even less marginal. My dream feature for D is a combination of static analysis, formal verification, and some brand of mutation testing guided by them (When we spoke about it last, Atila, you convinced me but it would take someone more dedicated than I to implement it)
Oct 11 2021
parent Nicholas Wilson <iamthewilsonator hotmail.com> writes:
On Monday, 11 October 2021 at 22:01:34 UTC, max haughton wrote:
 The decision to build languages as monolithic lumps of 
 specification, then a compiler, also phased in it's design, 
 while simple, I think will be a detriment in the post Moore's 
 law age, as it makes it very irritating to use and understand 
 the full muscle of the optimizer *in the right places* - and 
 fundamentally limits the potential of the/a language in a now 
 post-heterogenous world: you should he able to compile for a 
 GPU as part of the compiler a la a trait (This is an acceptable 
 use of the keyword, reflection is not).
I think a big problem from an exploratory perspective is that that is essentially impossible in a one-file-at-a-time compilation world and that to explore the space of possibilities far more people than the D community has. This afflicts C, C++, OpenCL, IPSC (1 file at a time, lack of anything other than immediate local context) CUDA, SYCL, (one file at a time, but lets do it twice! one for the host, one for the device) OpenMP (where premature outlining for device offloading has caused massive missed optimisation opportunity)
 I think D's worst feature is really a human tendency to avoid 
 language solutions for things. sumtype is a good library, but 
 it should be core language for example. Typecons.tuple is even 
 less marginal.
 __traits should've died years ago. Its continued existence 
 shows some level of paralysis.
in a static slice of time, yes. As a feature to easily add language functionality, without taking up more keywords, with minimal "feature space", its indispensable. It does however show that a program needs an API to the compiler during compilation. Is there a better way to do this? core.reflect and core.codegen seem like good steps.
Oct 11 2021
prev sibling next sibling parent Nicholas Wilson <iamthewilsonator hotmail.com> writes:
On Monday, 11 October 2021 at 15:59:10 UTC, Atila Neves wrote:
 I'm brainstorming about what I'll talk about at DConf, and 
 during a conversation with Walter I thought it might be cool to 
 talk about:

 * Worst features (in your opinion) in D
real, specifically fp80 real. Its slow, its almost always unintentional and phobos tends to use it way more than it should.
Oct 11 2021
prev sibling next sibling parent reply SealabJaster <sealabjaster gmail.com> writes:
On Monday, 11 October 2021 at 15:59:10 UTC, Atila Neves wrote:
 * Worst features implemented in a non-toy language
Everything to do with header files.
 * Worst features (in your opinion) in D
Autodecoding. Autodecoding. Autodecoding. Mutable by default. Template errors. (esp. `template instance func(T) where T = string cannot be instantiated with T = string`, or something along those lines, really, really, frustrates me) Inconsistent built-in property naming. (As a bonus: historical baggage) A fear of language solutions because of reasons, leading to annoying issues like std.sumtype being a PITA to debug sometimes due to bad error messages it can't really do anything about. `alias this` `abc => { return 123; }` should not be returning a function that returns a function.
 * Features you'd like to see in D
Language support for complex types: * sumtype and/or tagged unions. esp. in regards to pattern matching * optional types. * Maybe even a result/value_or_error type. ProtoObject point of usage, not just at definition. Being able to specify new/experimental functionality per-module, Being able to match structs against an `interface` or other such construct. As a language feature since a template version I can foresee eating my CPU. Allocators being better integrated with the language/phobos. Standard, de-facto interface/library/whatever for things like logging, databases, etc. Object initialisers: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/how-to-initialize-objects-by-using-an-object-initializer And most importantly, a plan for D's future and development, because personally I have 0 idea where D is trying to go now, what it's trying to be, who it tries to please, etc. What is our vision? What are our goals and ambitions for the language? I know it's basically completely infeasible but it's a fun thought experiment to think about what a "D3" could be like. Learning from the warts of the current language, removing historical issues, just a complete redesign whilst still being D.
Oct 11 2021
next sibling parent reply surlymoor <surlymoor cock.li> writes:
On Tuesday, 12 October 2021 at 03:17:08 UTC, SealabJaster wrote:
 `abc => { return 123; }` should not be returning a function 
 that returns a function.
https://dlang.org/changelog/2.098.0.html#ambiguous-lambda
sumtype and/or tagged unions. esp. in regards to pattern matching
I just want to be able to have a returned value be implicitly wrapped if its type is part of the `SumType` returned by the function. ```d // -preview=shortenedMethods is awesome SumType!(int, string) div(int a, int b) => b != 0 ? a : "Divisor is zero"; ```
Oct 11 2021
parent James Blachly <james.blachly gmail.com> writes:
On 10/12/21 1:29 AM, surlymoor wrote:
 I just want to be able to have a returned value be implicitly wrapped if 
 its type is part of the `SumType` returned by the function.
 
 ```d
 // -preview=shortenedMethods is awesome
 SumType!(int, string) div(int a, int b) => b != 0 ? a : "Divisor is zero";
 ```
Hear, hear
Oct 13 2021
prev sibling parent reply bauss <jj_1337 live.dk> writes:
On Tuesday, 12 October 2021 at 03:17:08 UTC, SealabJaster wrote:
 `abc => { return 123; }` should not be returning a function 
 that returns a function.
I agree with this so much, like why couldn't it have been made so you had to be explicit if you wanted to return a function? Like: `abc => &{ return 123; }`
Oct 11 2021
next sibling parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
On 10/12/21 2:14 AM, bauss wrote:
 On Tuesday, 12 October 2021 at 03:17:08 UTC, SealabJaster wrote:
 `abc => { return 123; }` should not be returning a function that 
 returns a function.
I agree with this so much, like why couldn't it have been made so you had to be explicit if you wanted to return a function? Like: `abc => &{ return 123; }`
Just FYI, the `abc => {}` syntax is just recently deprecated. https://dlang.org/changelog/2.098.0.html#ambiguous-lambda -Steve
Oct 12 2021
parent reply bauss <jj_1337 live.dk> writes:
On Tuesday, 12 October 2021 at 11:39:56 UTC, Steven Schveighoffer 
wrote:
 On 10/12/21 2:14 AM, bauss wrote:
 On Tuesday, 12 October 2021 at 03:17:08 UTC, SealabJaster 
 wrote:
 `abc => { return 123; }` should not be returning a function 
 that returns a function.
I agree with this so much, like why couldn't it have been made so you had to be explicit if you wanted to return a function? Like: `abc => &{ return 123; }`
Just FYI, the `abc => {}` syntax is just recently deprecated. https://dlang.org/changelog/2.098.0.html#ambiguous-lambda -Steve
Yeah, but I would rather that it was still allowed and that the semantics just changed. But obviously for good reason that isn't happening since it would break existing code.
Oct 12 2021
parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
On 10/12/21 8:42 AM, bauss wrote:
 On Tuesday, 12 October 2021 at 11:39:56 UTC, Steven Schveighoffer wrote:
 On 10/12/21 2:14 AM, bauss wrote:
 On Tuesday, 12 October 2021 at 03:17:08 UTC, SealabJaster wrote:
 `abc => { return 123; }` should not be returning a function that 
 returns a function.
I agree with this so much, like why couldn't it have been made so you had to be explicit if you wanted to return a function? Like: `abc => &{ return 123; }`
Just FYI, the `abc => {}` syntax is just recently deprecated. https://dlang.org/changelog/2.098.0.html#ambiguous-lambda -Steve
Yeah, but I would rather that it was still allowed and that the semantics just changed. But obviously for good reason that isn't happening since it would break existing code.
What would you change it to? `(abc) {return 123; }` already works. If you need to return a delegate, then `abc => () { return 123; }` works. We don't need 10 names for different kinds of snow. -Steve
Oct 12 2021
parent reply Paul Backus <snarwin gmail.com> writes:
On Tuesday, 12 October 2021 at 13:26:34 UTC, Steven Schveighoffer 
wrote:
 On 10/12/21 8:42 AM, bauss wrote:
 
 Yeah, but I would rather that it was still allowed and that 
 the semantics just changed.
 
 But obviously for good reason that isn't happening since it 
 would break existing code.
What would you change it to?
IMO the actual answer here is to deprecate the `{ /* ... */ }` syntax for function literals entirely. Not only is it confusing in the context of `=>` lambdas, it also creates a grammatical ambiguity between function literals and [block statements][1], which results in bugs like [issue 21619][2]. [1]: https://dlang.org/spec/grammar.html#BlockStatement [2]: https://issues.dlang.org/show_bug.cgi?id=21619
Oct 12 2021
parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
On 10/12/21 12:22 PM, Paul Backus wrote:
 On Tuesday, 12 October 2021 at 13:26:34 UTC, Steven Schveighoffer wrote:
 On 10/12/21 8:42 AM, bauss wrote:
 Yeah, but I would rather that it was still allowed and that the 
 semantics just changed.

 But obviously for good reason that isn't happening since it would 
 break existing code.
What would you change it to?
IMO the actual answer here is to deprecate the `{ /* ... */ }` syntax for function literals entirely. Not only is it confusing in the context of `=>` lambdas, it also creates a grammatical ambiguity between function literals and [block statements][1], which results in bugs like [issue 21619][2]. [1]: https://dlang.org/spec/grammar.html#BlockStatement [2]: https://issues.dlang.org/show_bug.cgi?id=21619
It's not a terrible idea. But I think there are hacks all over the place that enjoy the short syntax. One that I know of is to get the parent scope of a location: ```d alias parentScope = __traits(parent, {}); ``` Now, changing this to `__traits(parent, (){})` probably isn't a horrible update to require, but this code breakage is going to seem a little extraneous. -Steve
Oct 12 2021
parent Paul Backus <snarwin gmail.com> writes:
On Tuesday, 12 October 2021 at 17:49:10 UTC, Steven Schveighoffer 
wrote:
 It's not a terrible idea. But I think there are hacks all over 
 the place that enjoy the short syntax. One that I know of is to 
 get the parent scope of a location:

 ```d
 alias parentScope = __traits(parent, {});
 ```

 Now, changing this to `__traits(parent, (){})` probably isn't a 
 horrible update to require, but this code breakage is going to 
 seem a little extraneous.
This syntax is cute, but it's also extremely opaque, and confusing to beginners [1][2]. `(){}` is not much better, but it at least makes it clear that what you're looking at *isn't* a normal block statement, and you need to check the documentation/ask in the Learn forum/etc. to find out what it is. [1] https://forum.dlang.org/post/rzboijdfewehucrmztyc forum.dlang.org [2] https://forum.dlang.org/post/i40s2i$271n$1 digitalmars.com
Oct 12 2021
prev sibling parent user1234 <user1234 12.de> writes:
On Tuesday, 12 October 2021 at 06:14:40 UTC, bauss wrote:
 On Tuesday, 12 October 2021 at 03:17:08 UTC, SealabJaster wrote:
 `abc => { return 123; }` should not be returning a function 
 that returns a function.
I agree with this so much, like why couldn't it have been made so you had to be explicit if you wanted to return a function? Like: `abc => &{ return 123; }`
But you are do it explicitly, use the more verbose syntax: ``` alias a = abc => function{ return 123; }; ``` Also you have warning now
 Deprecation: Using `(args) => { ... }` to create a delegate 
 that returns a delegate is error-prone.
Oct 12 2021
prev sibling next sibling parent zjh <fqbqrr 163.com> writes:
On Monday, 11 October 2021 at 15:59:10 UTC, Atila Neves wrote:
 * Features you'd like to see in D

 Ideas? Examples?
What I want to change: I hope ,can directly use the standard library without 'GC'. I hope ,can also use `<>` as `template parameter` ,as `!()` more literal. I hope ,can use`...` like 'C++'. Hopefully, we can enhance 'betterC' or reduce 'GC', so that we can make good use of the 'standard library' or 'various advanced functions' I also hope that'd has a` simple, direct and easy to use GUI `Library of `hdpi` support.` GUI `is too important. I hope there are also `concept` constraints in in 'd' like in `C++`. I hope that the `d community` can change the `default attribute`. It is better to provide a tool for users to change their code. Be able to list important libraries separately and explain their purpose briefly. I hope we can collect more `good articles in the forum` into Wiki and other places. We should make good use of the `excellent posts` of people in the forum I hope we can pay attention to `Chinese users`, because Chinese people use `d` too little. I have translated many d's articles. I hope to give me some links so that the Chinese can also find `d's article`, so as not to always say that there are too few `Chinese documents`. At present, this is what I can think of , that's all.
Oct 11 2021
prev sibling next sibling parent Paulo Pinto <pjmlp progtools.org> writes:
On Monday, 11 October 2021 at 15:59:10 UTC, Atila Neves wrote:
 I'm brainstorming about what I'll talk about at DConf, and 
 during a conversation with Walter I thought it might be cool to 
 talk about:

 * Worst features implemented in a non-toy language
- Null terminated strings without length validation - No bounds checking by default - Implicit conversions between enumerations and numeric types - Lack on any sort of namespacing mechanism - Use of explicit pointers for out parameters
 * Worst features (in your opinion) in D
- inconsistent tag soup, e.g. safe vs pure, and the amount that almost feels like coding with Spring annotations - the __ prefixes for some runtime stuff like __traits - chasing the next computing fad while trying to find out the target audience
 * Features you'd like to see in D
- basically all the WIP stuff actually finalized before anything new gets started - safe by default (well I can still dream, until then safe: at the top of each module) when Andrei's book got published.
 Ideas? Examples?

 Thanks!
Oct 11 2021
prev sibling next sibling parent Kagamin <spam here.lot> writes:
Usage of unsigned integers as positive numbers.
cf. dotnet uses signed integers and the sky doesn't fall (it's 
32-bit int most of the time even). Granted some C and posix 
functions use signed integers when they need to return -1 
sentinel value. Recently I ported an oldish program to 64 bits, 
naturally it used narrowing conversions everywhere, but it was 
mostly signed integers, those aren't very sensitive to narrowing 
and extension. But the program crashed; when I looked at the 
cause, it was STL's string::find method returning unsigned 
integer even though it returns a sentinel value string::npos when 
the searched string isn't found, and the program there converted 
the returned value to uint, but then 
string::npos!=cast(uint)string::npos - unsigned integers are 
sensitive to extensions.
Oct 12 2021
prev sibling next sibling parent reply Superstar64 <Hexagonalstar64 gmail.com> writes:
On Monday, 11 October 2021 at 15:59:10 UTC, Atila Neves wrote:
 I'm brainstorming about what I'll talk about at DConf, and 
 during a conversation with Walter I thought it might be cool to 
 talk about:

 * Worst features implemented in a non-toy language
 * Worst features (in your opinion) in D
 * Features you'd like to see in D

 Ideas? Examples?

 Thanks!
Not necessarily a feature, but I think the absence of hindley milner type inference is a big one. I think that statically typed languages should adopt it or at the very least be influenced by it unless they have a really good reason not too. Types are completely optional in (vanilla) hindley milner. You can write code that looks like python and still have all the benefits of static typing. It also infers the most general type for the code you write. This makes your code as generic as possible unless you add a type annotation to make it less generic. I also think that it can help in language design in general. Weak typing and subtyping, features that are generally disliked are incompatible with hindley milner. It gives good answers to what the type of a null pointer and an empty array are without resorting to void pointers and void arrays which feel hacky.
Oct 12 2021
parent rikki cattermole <rikki cattermole.co.nz> writes:
On 13/10/2021 3:06 AM, Superstar64 wrote:
 Not necessarily a feature, but I think the absence of hindley milner 
 type inference is a big one. I think that statically typed languages 
 should adopt it or at the very least be influenced by it unless they 
 have a really good reason not too.
Hey hey hey, ML strikes again! ML + C syntax would have been a realllll winner back in the 70's I reckon, or today cos ya know that is the direction we are all going in.
Oct 12 2021
prev sibling next sibling parent reply Imperatorn <johan_forsberg_86 hotmail.com> writes:
On Monday, 11 October 2021 at 15:59:10 UTC, Atila Neves wrote:
 I'm brainstorming about what I'll talk about at DConf, and 
 during a conversation with Walter I thought it might be cool to 
 talk about:

 * Worst features implemented in a non-toy language
 * Worst features (in your opinion) in D
 * Features you'd like to see in D

 Ideas? Examples?

 Thanks!
foreach_reverse - worst "feature" mankind has produced
Oct 12 2021
parent reply Dr Machine Code <jckj33 gmail.com> writes:
On Tuesday, 12 October 2021 at 18:59:29 UTC, Imperatorn wrote:
 On Monday, 11 October 2021 at 15:59:10 UTC, Atila Neves wrote:
 I'm brainstorming about what I'll talk about at DConf, and 
 during a conversation with Walter I thought it might be cool 
 to talk about:

 * Worst features implemented in a non-toy language
 * Worst features (in your opinion) in D
 * Features you'd like to see in D

 Ideas? Examples?

 Thanks!
foreach_reverse - worst "feature" mankind has produced
why is it that bad? lol
Nov 14 2021
parent reply Imperatorn <johan_forsberg_86 hotmail.com> writes:
On Sunday, 14 November 2021 at 21:13:59 UTC, Dr Machine Code 
wrote:
 On Tuesday, 12 October 2021 at 18:59:29 UTC, Imperatorn wrote:
 On Monday, 11 October 2021 at 15:59:10 UTC, Atila Neves wrote:
 I'm brainstorming about what I'll talk about at DConf, and 
 during a conversation with Walter I thought it might be cool 
 to talk about:

 * Worst features implemented in a non-toy language
 * Worst features (in your opinion) in D
 * Features you'd like to see in D

 Ideas? Examples?

 Thanks!
foreach_reverse - worst "feature" mankind has produced
why is it that bad? lol
It's just so ugly 😅
Nov 14 2021
parent reply tsbockman <thomas.bockman gmail.com> writes:
On Sunday, 14 November 2021 at 23:51:00 UTC, Imperatorn wrote:
 On Sunday, 14 November 2021 at 21:13:59 UTC, Dr Machine Code 
 wrote:
 On Tuesday, 12 October 2021 at 18:59:29 UTC, Imperatorn wrote:
 foreach_reverse - worst "feature" mankind has produced
why is it that bad? lol
It's just so ugly 😅
The keyword isn't pretty, but it's useful, easy to understand, and actually works correctly. I'm sure you can think of something worse if you really try...
Nov 14 2021
parent reply Imperatorn <johan_forsberg_86 hotmail.com> writes:
On Monday, 15 November 2021 at 00:49:17 UTC, tsbockman wrote:
 On Sunday, 14 November 2021 at 23:51:00 UTC, Imperatorn wrote:
 On Sunday, 14 November 2021 at 21:13:59 UTC, Dr Machine Code 
 wrote:
 On Tuesday, 12 October 2021 at 18:59:29 UTC, Imperatorn wrote:
 foreach_reverse - worst "feature" mankind has produced
why is it that bad? lol
It's just so ugly 😅
The keyword isn't pretty, but it's useful, easy to understand, and actually works correctly. I'm sure you can think of something worse if you really try...
Well, obviously :) It was more of a joke, but it's still pretty cringe to see it
Nov 15 2021
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 15.11.21 10:29, Imperatorn wrote:
 On Monday, 15 November 2021 at 00:49:17 UTC, tsbockman wrote:
 On Sunday, 14 November 2021 at 23:51:00 UTC, Imperatorn wrote:
 On Sunday, 14 November 2021 at 21:13:59 UTC, Dr Machine Code wrote:
 On Tuesday, 12 October 2021 at 18:59:29 UTC, Imperatorn wrote:
 foreach_reverse - worst "feature" mankind has produced
why is it that bad? lol
It's just so ugly 😅
The keyword isn't pretty, but it's useful, easy to understand, and actually works correctly. I'm sure you can think of something worse if you really try...
Well, obviously :) It was more of a joke, but it's still pretty cringe to see it
The reason it exists is that reverse iteration over unsigned types is notoriously error prone. I think it's pretty nice to have this built in, knowing that it will be directly transformed into a simple for loop even in debug builds. It also allows easily reversing the order of iteration of any foreach loop, no matter which form. In particular, there is `static foreach_reverse`.
Nov 15 2021
next sibling parent reply Imperatorn <johan_forsberg_86 hotmail.com> writes:
On Monday, 15 November 2021 at 12:41:51 UTC, Timon Gehr wrote:
 On 15.11.21 10:29, Imperatorn wrote:
 On Monday, 15 November 2021 at 00:49:17 UTC, tsbockman wrote:
 [...]
Well, obviously :) It was more of a joke, but it's still pretty cringe to see it
The reason it exists is that reverse iteration over unsigned types is notoriously error prone. I think it's pretty nice to have this built in, knowing that it will be directly transformed into a simple for loop even in debug builds. It also allows easily reversing the order of iteration of any foreach loop, no matter which form. In particular, there is `static foreach_reverse`.
What's wrong about retro? Too retro :D
Nov 15 2021
next sibling parent reply Paul Backus <snarwin gmail.com> writes:
On Monday, 15 November 2021 at 14:02:42 UTC, Imperatorn wrote:
 What's wrong about retro? Too retro :D
std.range.retro is honestly just a bad name. It should have been `reversed`, or maybe `reverser`.
Nov 15 2021
next sibling parent Basile B. <b2.temp gmx.com> writes:
On Monday, 15 November 2021 at 14:09:53 UTC, Paul Backus wrote:
 On Monday, 15 November 2021 at 14:02:42 UTC, Imperatorn wrote:
 What's wrong about retro? Too retro :D
std.range.retro is honestly just a bad name. It should have been `reversed`, or maybe `reverser`.
That reverser thing could have been a builtin property e.g `.reverser`, problem is that the expression that gives a foreach range (https://dlang.org/spec/statement.html#foreach-range-statement) is a bit degenerated for now: `LwrExpression .. UprExpression` is actually not an expression at all thus `(LwrExpression ..UprExpression).reverser` cant work. But Ideally D could get rid of that `foreach_reverse` keyword with a property. ```d foreach (i; (0 .. length).reverser){} foreach (e; elems.reverser){} ``` Off topic side node : the old [DIP 58](https://wiki.dlang.org/DIP58) shows that the idea to have the `..` D operator is not new but apparently the case of simplifying `foreach` was not a goal.
Nov 15 2021
prev sibling parent deadalnix <deadalnix gmail.com> writes:
On Monday, 15 November 2021 at 14:09:53 UTC, Paul Backus wrote:
 On Monday, 15 November 2021 at 14:02:42 UTC, Imperatorn wrote:
 What's wrong about retro? Too retro :D
std.range.retro is honestly just a bad name. It should have been `reversed`, or maybe `reverser`.
``` alias reversed = retro; ``` Problem solved :)
Dec 17 2021
prev sibling parent Timon Gehr <timon.gehr gmx.ch> writes:
On 15.11.21 15:02, Imperatorn wrote:
 On Monday, 15 November 2021 at 12:41:51 UTC, Timon Gehr wrote:
 On 15.11.21 10:29, Imperatorn wrote:
 On Monday, 15 November 2021 at 00:49:17 UTC, tsbockman wrote:
 [...]
Well, obviously :) It was more of a joke, but it's still pretty cringe to see it
The reason it exists is that reverse iteration over unsigned types is notoriously error prone. I think it's pretty nice to have this built in, knowing that it will be directly transformed into a simple for loop even in debug builds. It also allows easily reversing the order of iteration of any foreach loop, no matter which form. In particular, there is `static foreach_reverse`.
What's wrong about retro? Too retro :D
My post was literally a description of drawbacks of retro. There's nothing wrong with it in particular, but the main drawback is that in general you need to do more than slap retro on the aggregate in order to get the correct semantics. Tuple!(int,int)[] a=...; foreach(i,x;a){} // reverse this!
Nov 15 2021
prev sibling parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
On 11/15/21 7:41 AM, Timon Gehr wrote:
 On 15.11.21 10:29, Imperatorn wrote:
 On Monday, 15 November 2021 at 00:49:17 UTC, tsbockman wrote:
 On Sunday, 14 November 2021 at 23:51:00 UTC, Imperatorn wrote:
 On Sunday, 14 November 2021 at 21:13:59 UTC, Dr Machine Code wrote:
 On Tuesday, 12 October 2021 at 18:59:29 UTC, Imperatorn wrote:
 foreach_reverse - worst "feature" mankind has produced
why is it that bad? lol
It's just so ugly 😅
The keyword isn't pretty, but it's useful, easy to understand, and actually works correctly. I'm sure you can think of something worse if you really try...
Well, obviously :) It was more of a joke, but it's still pretty cringe to see it
The reason it exists is that reverse iteration over unsigned types is notoriously error prone. I think it's pretty nice to have this built in, knowing that it will be directly transformed into a simple for loop even in debug builds. It also allows easily reversing the order of iteration of any foreach loop, no matter which form. In particular, there is `static foreach_reverse`.
Although it's fallen mostly out of style, the reason I hated `foreach_reverse` is because it used to be applicable to delegate iteration, but just iterates forward (I've just checked and it's deprecated, but not disabled). I think I can count on one finger (and you can guess which one) the times I've used `foreach_reverse`. -Steve
Nov 15 2021
next sibling parent Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= <ola.fosheim.grostad gmail.com> writes:
On Monday, 15 November 2021 at 14:19:00 UTC, Steven Schveighoffer 
wrote:
 I think I can count on one finger (and you can guess which one) 
 the times I've used `foreach_reverse`.
Pinkie?
Nov 15 2021
prev sibling next sibling parent Adam D Ruppe <destructionator gmail.com> writes:
On Monday, 15 November 2021 at 14:19:00 UTC, Steven Schveighoffer 
wrote:
 I think I can count on one finger (and you can guess which one) 
 the times I've used `foreach_reverse`.
~/arsd$ grep foreach_reverse *.d | wc 34 it p useful actually.
Nov 15 2021
prev sibling parent reply Quirin Schroll <qs.il.paperinik gmail.com> writes:
On Monday, 15 November 2021 at 14:19:00 UTC, Steven Schveighoffer 
wrote:
 On 11/15/21 7:41 AM, Timon Gehr wrote:
 In particular, there is `static foreach_reverse`.
Although it's fallen mostly out of style, the reason I hated `foreach_reverse` is because it used to be applicable to delegate iteration, but just iterates forward (I've just checked and it's deprecated, but not disabled).
Maybe this is older. When I came to D around 2015, I learned that there is `opApply` for forward iteration (`foreach`) and `opApplyReverse` for reverse iteration (`foreach_reverse`). I just tried defining a struct with `opApply`, but no `opApplyReverse`, and then `foreach_reverse` on an instance (on run.dlang.io). Doesn't work.
Dec 18 2021
parent Steven Schveighoffer <schveiguy gmail.com> writes:
On 12/18/21 2:54 PM, Quirin Schroll wrote:
 On Monday, 15 November 2021 at 14:19:00 UTC, Steven Schveighoffer wrote:
 On 11/15/21 7:41 AM, Timon Gehr wrote:
 In particular, there is `static foreach_reverse`.
Although it's fallen mostly out of style, the reason I hated `foreach_reverse` is because it used to be applicable to delegate iteration, but just iterates forward (I've just checked and it's deprecated, but not disabled).
Maybe this is older. When I came to D around 2015, I learned that there is `opApply` for forward iteration (`foreach`) and `opApplyReverse` for reverse iteration (`foreach_reverse`). I just tried defining a struct with `opApply`, but no `opApplyReverse`, and then `foreach_reverse` on an instance (on run.dlang.io). Doesn't work.
You can foreach an appropriately typed delegate too. e.g. ``` struct S { int byKey(int delegate(int) dg) { return 0; } } void main() { S s; foreach(i; &s.byKey) {} foreach_reverse(i; &s.byKey) {} // Deprecated, still iterates forwards } ``` https://run.dlang.io/is/G3KUfl As I said, it's fallen out of style. I used this [in my dcollections library](https://github.com/schveiguy/dcollections/blob/82118cfd4faf3f1ad77df078d279f1b964f274e7/co cepts.txt#L81-L100) though. -Steve
Dec 21 2021
prev sibling next sibling parent reply "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Mon, Oct 11, 2021 at 03:59:10PM +0000, Atila Neves via Digitalmars-d wrote:
 I'm brainstorming about what I'll talk about at DConf, and during a
 conversation with Walter I thought it might be cool to talk about:
 
 * Worst features implemented in a non-toy language
From languages I know:
- C: - Implicit decay of array to pointer. - Null-terminated strings (corruption of your string data == buffer overflow exploit waiting to happen). - Pointer syntax: the `*` grammatically attaches to the identifier rather than the type name, which causes all sorts of totally needless syntactic convolutions like the unreadable function pointer syntax. (Yes, I know how it works, I've been writing them for 20+ years and I know them like the back of my hand; but it is nevertheless a Bad Idea(tm).) Not to mention how easily beginners mess it up. - C++: - Template syntax (using `<>` for template parameters/arguments has got to be the worst syntax choice made in the last 30 years, making C++ unlexible until it's first parsed). - Null-terminated strings (one of the worst things to inherit from C). - Free-for-all, wild-wild-west operator overloading that lets you define, e.g., <, <=, >, >= in completely inconsistent, incompatible ways. Not to mention the amount of boilerplate necessary to implement these operators in a consistent way, leading to more opportunities for human error. - Perl: - Sigils: $x, x, %x refer to different things. Worse yet, $x{y} dereferences %x, not $x, and $x[y] dereferences x rather than $x. (Argh...) (I actually *like* the rationale behind sigils, but the way they're implemented is just ... argh...) - JS: - Dynamic typing. Leads to all kinds of bugs and runtime exceptions that eventually compel you to write checks, that ultimately boil down to reinventing static typing in an ad hoc way. As someone once said, dynamic typing is just static typing with only a single type. - `===` vs `==`. - WAT-eliciting behavior of built-in operators: like `[] + []` producing an empty string, `[] + {}` producing `[object Object]` (which is a *string*, not an actual object!) and `{} + []` producing 0.
 * Worst features (in your opinion) in D
- The integer promotion/casting mess. I understand that C compatibility is very important, but things have seriously gone off the rails when you get things like: ubyte x; x = -x; // compile error - Autodecoding. - Half-baked features like `shared`. It kinda-sorta works, its behaviour is by design, casts are intentional, etc.. But it leaves you with the feeling of incompleteness. It promises thread safety (or at least to help towards that goal), but when you use it you feel like you're given parts of some IKEA furniture without nails, screws, or bolts, which you have to provide on your own (and of course, assembly is also DIY, and if it falls apart it's your fault, not ours). - In the same vein, property. It's been how many years now, when are we going to get a comprehensive solution (or, at the very least, when will this sad creature with missing limbs finally be euthanized for mercy's sake)?
 * Features you'd like to see in D
[...] - C++ concepts-like feature of specifying the expected interface of a template parameter. - Yes, sig constraints fit the bill, kinda-sorta. But it leads to poor, unhelpful error messages. Yes, this can be fixed by using static if, pragma(msg), etc., but this requires a lot of extra work on the part of the user which should have been handled by the language. - Yes, there's a dub package that kinda-sorta does this. But again, this is something that should have been done by the language. - More procedural type manipulations. `static foreach` is great; it eliminated a bunch of cases where you'd need to use recursive templates. It'd be nice to have procedural manipulations of types/aliases/etc. as well. Kinda like Stefan's type functions, but more integrated into the language and streamlined with other D features. Basically, get rid of recursive templates except where they're absolutely, unavoidably, necessary. - More complete outworking of features that require deep language support, like `shared` or property or [insert your favorite half-baked D feature here]. Provide a comprehensive package that actually enables you to get stuff done without having to buy your own nails, your own hammer, and assemble things yourself, and that provide some solid guarantees that doesn't just leave you holding the pieces when things break. - Extend `if (auto x = initializer())` to apply to complex conditions as well, e.g.: if (someClause && (auto x = initializer()) && (auto y = initializer2())) { /* use x and y here */ } T -- Turning your clock 15 minutes ahead won't cure lateness---you're just making time go faster!
Oct 12 2021
next sibling parent reply Paul Backus <snarwin gmail.com> writes:
On Tuesday, 12 October 2021 at 19:41:57 UTC, H. S. Teoh wrote:
 - C++ concepts-like feature of specifying the expected 
 interface of a
   template parameter.
    - Yes, sig constraints fit the bill, kinda-sorta.  But it 
 leads to
      poor, unhelpful error messages.  Yes, this can be fixed by 
 using
      static if, pragma(msg), etc., but this requires a lot of 
 extra work
      on the part of the user which should have been handled by 
 the
      language.
    - Yes, there's a dub package that kinda-sorta does this. But 
 again,
      this is something that should have been done by the 
 language.
You can get about 90% of the way to better constraint errors with existing language features: struct Check { bool passed; string message; T opCast(T : bool)() { return passed; } } enum hasFoo(T) = Check( __traits(hasMember, T, "foo"), "`" ~ T.stringof ~ "` must have a member named `foo`" ); struct Pass { int foo; } struct Fail { int bar; } // Can check with static assert static assert(hasFoo!Pass); static assert(!hasFoo!Fail); // Works in constraints auto getFoo(T)(T input) if (hasFoo!T) { return input.foo; } static assert(__traits(compiles, Pass().getFoo)); static assert(!__traits(compiles, Fail().getFoo)); // Can check error message pragma(msg, hasFoo!Fail.message); The only thing missing is a way to get the compiler to print out your custom message, instead of (or in addition to) the default "must satisfy `hasFoo!T`" message. I plan to write a DIP for this as soon as I am done with nodiscard.
Oct 12 2021
parent reply russhy <russhy gmail.com> writes:
On Tuesday, 12 October 2021 at 20:29:32 UTC, Paul Backus wrote:
 On Tuesday, 12 October 2021 at 19:41:57 UTC, H. S. Teoh wrote:
 - C++ concepts-like feature of specifying the expected 
 interface of a
   template parameter.
    - Yes, sig constraints fit the bill, kinda-sorta.  But it 
 leads to
      poor, unhelpful error messages.  Yes, this can be fixed 
 by using
      static if, pragma(msg), etc., but this requires a lot of 
 extra work
      on the part of the user which should have been handled by 
 the
      language.
    - Yes, there's a dub package that kinda-sorta does this. 
 But again,
      this is something that should have been done by the 
 language.
You can get about 90% of the way to better constraint errors with existing language features: struct Check { bool passed; string message; T opCast(T : bool)() { return passed; } } enum hasFoo(T) = Check( __traits(hasMember, T, "foo"), "`" ~ T.stringof ~ "` must have a member named `foo`" ); struct Pass { int foo; } struct Fail { int bar; } // Can check with static assert static assert(hasFoo!Pass); static assert(!hasFoo!Fail); // Works in constraints auto getFoo(T)(T input) if (hasFoo!T) { return input.foo; } static assert(__traits(compiles, Pass().getFoo)); static assert(!__traits(compiles, Fail().getFoo)); // Can check error message pragma(msg, hasFoo!Fail.message); The only thing missing is a way to get the compiler to print out your custom message, instead of (or in addition to) the default "must satisfy `hasFoo!T`" message. I plan to write a DIP for this as soon as I am done with nodiscard.
templates doesn't work with DCD/DSymbol because it doesn't do semantic analysis, so that kind of features is impossible implement for tooling right now.. this is why things like tagged union (sumtype) and multiple return type should be implemented as language features, that way it is easier to parse (on top of other benefits) please push for language feature! your work on sumtype was great, but there is much more to gain from upgrading it as a language feature
Oct 12 2021
parent reply Paul Backus <snarwin gmail.com> writes:
On Wednesday, 13 October 2021 at 01:56:19 UTC, russhy wrote:
 this is why things like tagged union (sumtype) and multiple 
 return type should be implemented as language features, that 
 way it is easier to parse (on top of other benefits)

 please push for language feature! your work on sumtype was 
 great, but there is much more to gain from upgrading it as a 
 language feature
If anyone wants to work on a DIP and implementation for built-in sum types, they will have my full support. Unfortunately, I do not have the time or the skills necessary to lead such a project myself.
Oct 12 2021
next sibling parent max haughton <maxhaton gmail.com> writes:
On Wednesday, 13 October 2021 at 02:39:47 UTC, Paul Backus wrote:
 On Wednesday, 13 October 2021 at 01:56:19 UTC, russhy wrote:
 this is why things like tagged union (sumtype) and multiple 
 return type should be implemented as language features, that 
 way it is easier to parse (on top of other benefits)

 please push for language feature! your work on sumtype was 
 great, but there is much more to gain from upgrading it as a 
 language feature
If anyone wants to work on a DIP and implementation for built-in sum types, they will have my full support. Unfortunately, I do not have the time or the skills necessary to lead such a project myself.
I think such a feature would benefit from having tuple syntax and semantics done first. Timon did have a DIP for tuples.
Oct 12 2021
prev sibling parent reply russhy <russhy gmail.com> writes:
On Wednesday, 13 October 2021 at 02:39:47 UTC, Paul Backus wrote:
 On Wednesday, 13 October 2021 at 01:56:19 UTC, russhy wrote:
 this is why things like tagged union (sumtype) and multiple 
 return type should be implemented as language features, that 
 way it is easier to parse (on top of other benefits)

 please push for language feature! your work on sumtype was 
 great, but there is much more to gain from upgrading it as a 
 language feature
If anyone wants to work on a DIP and implementation for built-in sum types, they will have my full support. Unfortunately, I do not have the time or the skills necessary to lead such a project myself.
it worth doing the extra kilometer to avoid having the situation we have currently, for yet another std package going easy road for what short term benefits? other languages have tagged union built into the language, same for nullable, it's proven to be very useful std should serve for bigger (missing) purposes - Filesystem package: std.fs - Networking package: std.net - Event Loop package: std.event - Graphics package: std.gfx - Datastructure package: std.collections - Memory package: std.mem not for little things that doesn't have any purpose other than inflating the std with tiny packages that everyone already has implemented in their own "utils" module it's to get issues like this: https://forum.dlang.org/thread/gyzbciyzrywphxbbhdpn forum.dlang.org then even more no..
Oct 13 2021
parent reply Paul Backus <snarwin gmail.com> writes:
On Thursday, 14 October 2021 at 01:33:59 UTC, russhy wrote:
 On Wednesday, 13 October 2021 at 02:39:47 UTC, Paul Backus 
 wrote:
 If anyone wants to work on a DIP and implementation for 
 built-in sum types, they will have my full support. 
 Unfortunately, I do not have the time or the skills necessary 
 to lead such a project myself.
it worth doing the extra kilometer to avoid having the situation we have currently, for yet another std package going easy road for what short term benefits? other languages have tagged union built into the language, same for nullable, it's proven to be very useful
Sometimes the difference is not between "easy" and "hard", but between "possible" and "impossible". If you have never written a DIP, or contributed to DMD, it is easy to underestimate the amount of work required to add a new language feature to D. I have done both, and I can say with confidence that adding built-in sum types will take *at least* 10x the effort it has taken to get std.sumtype to its current state. I would love for D to have built-in sum types, believe me. But adding them is simply too big a project for a single volunteer like me to take on. If you really want this to happen, I think your best bet is to convince Walter and the D Foundation to make it an official priority, and sponsor someone to work on it.
Oct 13 2021
parent SealabJaster <sealabjaster gmail.com> writes:
On Thursday, 14 October 2021 at 02:13:00 UTC, Paul Backus wrote:
 ...
 If you really want this to happen, I think your best bet is to 
 convince Walter and the D Foundation to make it an official 
 priority, and sponsor someone to work on it.
Possibly, in a parallel universe. I guess that kind of goes for most of the suggested language additions though as well which isn't very... comforting.
Oct 13 2021
prev sibling parent jmh530 <john.michael.hall gmail.com> writes:
On Tuesday, 12 October 2021 at 19:41:57 UTC, H. S. Teoh wrote:
 [snip]
 * Features you'd like to see in D
[...] - C++ concepts-like feature of specifying the expected interface of a template parameter. - Yes, sig constraints fit the bill, kinda-sorta. But it leads to poor, unhelpful error messages. Yes, this can be fixed by using static if, pragma(msg), etc., but this requires a lot of extra work on the part of the user which should have been handled by the language. - Yes, there's a dub package that kinda-sorta does this. But again, this is something that should have been done by the language.
I've become more sympathetic to this. The main argument against DIP 1023 (resolution of template alias parameters in template functions) boiled down to "why not use signature constraints." Something like Concepts could be an alternative solution to the problems addressed in that DIP (though that may not be the only way to resolve them). Runtime & static polymorphism comes in different types and flavors. D has class, which is similar to how C++ and Java work (ignoring some details). So we can group these together in a run-time polymorphism. D's interface is similar to that, but doesn't do exactly the same thing and is different from Go's interface and Rust's traits system. Concepts as a form of static polymorphism are in a different category as well. But how do we group the categories in a way that makes sense?
Oct 12 2021
prev sibling next sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 10/11/21 5:59 PM, Atila Neves wrote:
 ...
This is likely to be incomplete or overly abstract, but here's my approximate take:
 * Worst features implemented in a non-toy language
- unsound type system - undefined behavior for categories of errors other than memory corruption - inappropriately nondeterministic semantics - mutable aliasing by default (mutability is fine, aliasing is the issue) - pointer arithmetic without appropriate type system support - imprecise type system (>40 years behind state of the art) - non-orthogonal language definition - null pointers without appropriate type system support - Turing-complete constructors
 * Worst features (in your opinion) in D
- undefined behavior for categories of errors other than memory corruption, e.g. 'assert' - safe `void` initialization - safe extern(C) function prototypes - inout - nondeterministic floating-point semantics - forward reference errors/ambiguities (arising from underspecification of compile-time introspection) - .init - separation of templates and CTFE - null pointers - Turing-complete constructors - Object - interaction of type qualifiers with reference types - underspecification of type/function qualifiers - template syntax is inconsistent between declaration and call site - alias this (it uses lookup rules different from import) - slicing and indexing of sequences is magic, there is no way to slice a library tuple without decaying into an auto-expanding sequence
 * Features you'd like to see in D
- built-in tuples/products with standard syntax - built-in tagged unions/sums, nullable, algebraic data types - pattern matching - real support for linear/affine typing - named parameters with support for perfect forwarding and compile-time introspection - built-in duck-typed record types playing nice with named parameters - type classes / some standard way to add UFCS methods to a type from another module that are then visible in an instantiated template from a third module - uniform syntax for function definition, in particular `int add(int a,int b)=>a+b;` (-preview=shortenedMethods) - `let Statement in Expression` expression - `Expression where Statement` expression - mixin identifiers - __local, static break and continue (https://github.com/dlang/DIPs/blob/master/DIPs/accepted/DIP1010.md) - template literals - static opIndex/opSlice - AST introspection - consistent treatment of operators for built-in types, e.g. 1.opBinary!"+"(2) should work. - operator overloading should combine orthogonally with UFCS - better support for subtyping (expose the concept to user-defined types, e.g., Range!(const(T)) could be a subtype of const(Range!T)) and any other features required to support a good container library - async/await (or similar) - yield (or similar) - range literals - more lightweight coroutines - ProtoObject - special treatment of qualified types, in particular qualified reference types (e.g. `immutable` classes should allow conversion of references from `immutable` to mutable) - non-deterministic semantics, with as little undefined behavior as possible, in particular for type/function qualifiers - compile-time fixed-point support (e.g., with struct S(T){ T* next; }, fix!S gives a singly linked list). - flow-sensitive typing - strong variable updates (probably not happening) - non-lexical variable lifetimes (probably not happening) - parametric polymorphism, in particular for type qualifiers (probably not happening) - some amount of dependent types (dreaming now)
Oct 12 2021
next sibling parent reply surlymoor <surlymoor cock.li> writes:
On Tuesday, 12 October 2021 at 21:38:48 UTC, Timon Gehr wrote:
 - .init
Is the issue default initialization or that the property is named `init`?
Oct 12 2021
next sibling parent Timon Gehr <timon.gehr gmx.ch> writes:
On 10/12/21 11:50 PM, surlymoor wrote:
 On Tuesday, 12 October 2021 at 21:38:48 UTC, Timon Gehr wrote:
 - .init
Is the issue default initialization or that the property is named `init`?
Uninitialized variables are not an option, so default initialization and/or some flow analysis unfortunately seem to be necessary given the limited nature of D's lexical scoping rules. The issue is that every user-defined type is by default assumed to have a default state. It's null pointers with extra steps. I'm not a big fan of the possibility of accidentally hiding a type's `init` using a user-defined field, but this is a lesser issue and at least this way it can be disabled, though I am not absolutely sure that this completely denies access.
Oct 12 2021
prev sibling parent reply Q. Schroll <qs.il.paperinik gmail.com> writes:
On Tuesday, 12 October 2021 at 21:50:11 UTC, surlymoor wrote:
 On Tuesday, 12 October 2021 at 21:38:48 UTC, Timon Gehr wrote:
 - .init
Is the issue default initialization or that the property is named `init`?
The fact that the default value of a type `T` is `T.init` and `init` isn't even a keyword leading to all the problems it has, when it could have been `default(T)` is really embarrassing.
Nov 15 2021
parent Timon Gehr <timon.gehr gmx.ch> writes:
On 15.11.21 19:04, Q. Schroll wrote:
 On Tuesday, 12 October 2021 at 21:50:11 UTC, surlymoor wrote:
 On Tuesday, 12 October 2021 at 21:38:48 UTC, Timon Gehr wrote:
 - .init
Is the issue default initialization or that the property is named `init`?
The fact that the default value of a type `T` is `T.init` and `init` isn't even a keyword leading to all the problems it has, when it could have been `default(T)` is really embarrassing.
That's not close to all the problems and at least you can ` disable enum init = 0;` now.
Nov 15 2021
prev sibling next sibling parent Timon Gehr <timon.gehr gmx.ch> writes:
On 10/12/21 11:38 PM, Timon Gehr wrote:
 
 * Worst features (in your opinion) in D 
- local imports that implicitly hide symbols from outer scopes in current module
Oct 12 2021
prev sibling next sibling parent user1234 <user1234 12.de> writes:
On Tuesday, 12 October 2021 at 21:38:48 UTC, Timon Gehr wrote:
 On 10/11/21 5:59 PM, Atila Neves wrote:
 ...
This is likely to be incomplete or overly abstract, but here's my approximate take:
 * Worst features implemented in a non-toy language
- unsound type system - undefined behavior for categories of errors other than memory corruption - inappropriately nondeterministic semantics - mutable aliasing by default (mutability is fine, aliasing is the issue) - pointer arithmetic without appropriate type system support - imprecise type system (>40 years behind state of the art) - non-orthogonal language definition - null pointers without appropriate type system support - Turing-complete constructors
Please mention the language for each point. I think that "inappropriately nondeterministic semantics" can be JS.
Oct 12 2021
prev sibling next sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 10/12/2021 2:38 PM, Timon Gehr wrote:
 - non-lexical variable lifetimes (probably not happening)
It's already implemented for live.
Oct 15 2021
next sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 10/16/21 1:12 AM, Walter Bright wrote:
 On 10/12/2021 2:38 PM, Timon Gehr wrote:
 - non-lexical variable lifetimes (probably not happening)
It's already implemented for live.
Specifically, I would like it to influence scoping. ```d int x=2; int y=move(x); int z=x; // error: undefined identifier x (was moved away) int y=move(y); // ok ```
Nov 09 2021
next sibling parent reply Stefan Koch <uplink.coder gmail.com> writes:
On Wednesday, 10 November 2021 at 07:09:34 UTC, Timon Gehr wrote:
 On 10/16/21 1:12 AM, Walter Bright wrote:
 On 10/12/2021 2:38 PM, Timon Gehr wrote:
 - non-lexical variable lifetimes (probably not happening)
It's already implemented for live.
Specifically, I would like it to influence scoping. ```d int x=2; int y=move(x); int z=x; // error: undefined identifier x (was moved away) int y=move(y); // ok ```
That would be a good start. I would support that.
Nov 10 2021
parent reply Sebastiaan Koppe <mail skoppe.eu> writes:
On Wednesday, 10 November 2021 at 14:15:58 UTC, Stefan Koch wrote:
 On Wednesday, 10 November 2021 at 07:09:34 UTC, Timon Gehr 
 wrote:
 Specifically, I would like it to influence scoping.

 ```d
 int x=2;
 int y=move(x);
 int z=x; // error: undefined identifier x (was moved away)

 int y=move(y); // ok
 ```
That would be a good start. I would support that.
Yeah, that would be lovely.
Nov 10 2021
parent reply "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Wed, Nov 10, 2021 at 02:17:28PM +0000, Sebastiaan Koppe via Digitalmars-d
wrote:
 On Wednesday, 10 November 2021 at 14:15:58 UTC, Stefan Koch wrote:
 On Wednesday, 10 November 2021 at 07:09:34 UTC, Timon Gehr wrote:
 Specifically, I would like it to influence scoping.
 
 ```d
 int x=2;
 int y=move(x);
 int z=x; // error: undefined identifier x (was moved away)
 
 int y=move(y); // ok
 ```
That would be a good start. I would support that.
Yeah, that would be lovely.
That would allow a better implementation of ownership tracking. T -- People walk. Computers run.
Nov 10 2021
parent reply Stefan Koch <uplink.coder gmail.com> writes:
On Wednesday, 10 November 2021 at 17:05:20 UTC, H. S. Teoh wrote:
 On Wed, Nov 10, 2021 at 02:17:28PM +0000, Sebastiaan Koppe via 
 Digitalmars-d wrote:
 On Wednesday, 10 November 2021 at 14:15:58 UTC, Stefan Koch 
 wrote:
 On Wednesday, 10 November 2021 at 07:09:34 UTC, Timon Gehr 
 wrote:
 Specifically, I would like it to influence scoping.
 
 ```d
 int x=2;
 int y=move(x);
 int z=x; // error: undefined identifier x (was moved away)
 
 int y=move(y); // ok
 ```
That would be a good start. I would support that.
Yeah, that would be lovely.
That would allow a better implementation of ownership tracking. T
Other way around. It requires better compiler ownership tracking.
Nov 10 2021
parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Wed, Nov 10, 2021 at 05:55:47PM +0000, Stefan Koch via Digitalmars-d wrote:
 On Wednesday, 10 November 2021 at 17:05:20 UTC, H. S. Teoh wrote:
 On Wed, Nov 10, 2021 at 02:17:28PM +0000, Sebastiaan Koppe via
 Digitalmars-d wrote:
 On Wednesday, 10 November 2021 at 14:15:58 UTC, Stefan Koch wrote:
 On Wednesday, 10 November 2021 at 07:09:34 UTC, Timon Gehr >
wrote:
 Specifically, I would like it to influence scoping.
 ```d
int x=2; int y=move(x); int z=x; // error: undefined identifier x (was moved away)
 int y=move(y); // ok
``` That would be a good start. I would support that.
Yeah, that would be lovely.
That would allow a better implementation of ownership tracking.
[...]
 Other way around.
 It requires better compiler ownership tracking.
That's what I meant. :D If the compiler has this tracking, then it becomes possible to implement a simple ownership-tracking pointer wrapper type in user code. T -- Stop staring at me like that! It's offens... no, you'll hurt your eyes!
Nov 10 2021
prev sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 11/9/2021 11:09 PM, Timon Gehr wrote:
 On 10/16/21 1:12 AM, Walter Bright wrote:
 On 10/12/2021 2:38 PM, Timon Gehr wrote:
 - non-lexical variable lifetimes (probably not happening)
It's already implemented for live.
Specifically, I would like it to influence scoping. ```d int x=2; int y=move(x); int z=x; // error: undefined identifier x (was moved away)
live currently does that for pointers, but not for non-pointers. What's the use case for it?
 int y=move(y); // ok
 ```
I see what you mean, but since D disallows: int x; { int x; } which prevents a number of bugs, so I can't see allowing that.
Dec 28 2021
next sibling parent reply Petar Kirov [ZombineDev] <petar.p.kirov gmail.com> writes:
On Wednesday, 29 December 2021 at 05:09:33 UTC, Walter Bright 
wrote:
 On 11/9/2021 11:09 PM, Timon Gehr wrote:
 On 10/16/21 1:12 AM, Walter Bright wrote:
 On 10/12/2021 2:38 PM, Timon Gehr wrote:
 - non-lexical variable lifetimes (probably not happening)
It's already implemented for live.
Specifically, I would like it to influence scoping. ```d int x=2; int y=move(x); int z=x; // error: undefined identifier x (was moved away)
live currently does that for pointers, but not for non-pointers. What's the use case for it?
The typestate [1] design pattern. In languages that support some form of affine types [2] like Rust (*), this design pattern can be used to prevent classes of programmer errors at compile-time, while the best C++ and D can do is use `assert` at run-time to facilitate detecting them. Here's a few articles that showcase this in Rust: * https://cliffle.com/blog/rust-typestate/ * https://rustype.github.io/notes/notes/rust-typestate-series/rust-typestate-part-1 * https://docs.rs/typestate/latest/typestate/ (*) Technically, affine types are about using a variable at most once. In Rust, if a type doesn't implement the Copy / Clone traits [3], variables of that type have move semantics - that is, they can't be used after they have been passed to a function that takes them by value (passing ownership). But they can be still passed multiple times to functions take them by reference (borrowing). [1]: https://en.wikipedia.org/wiki/Typestate_analysis [2]: https://en.wikipedia.org/wiki/Substructural_type_system [3]: https://doc.rust-lang.org/std/marker/trait.Copy.html
Dec 29 2021
parent Walter Bright <newshound2 digitalmars.com> writes:
On 12/29/2021 12:10 AM, Petar Kirov [ZombineDev] wrote:
 The typestate [1] design pattern. In languages that support some form of
affine 
 types [2] like Rust (*), this design pattern can be used to prevent classes of 
 programmer errors at compile-time, while the best C++ and D can do is use 
 `assert` at run-time to facilitate detecting them. Here's a few articles that 
 showcase this in Rust:
 
 * https://cliffle.com/blog/rust-typestate/
 * https://rustype.github.io/notes/notes/rust-typestate-series/rust-typestate-part-1
 * https://docs.rs/typestate/latest/typestate/
 
 (*) Technically, affine types are about using a variable at most once. In
Rust, 
 if a type doesn't implement the Copy / Clone traits [3], variables of that
type 
 have move semantics - that is, they can't be used after they have been passed
to 
 a function that takes them by value (passing ownership). But they can be still 
 passed multiple times to functions take them by reference (borrowing).
 
 [1]: https://en.wikipedia.org/wiki/Typestate_analysis
 [2]: https://en.wikipedia.org/wiki/Substructural_type_system
 [3]: https://doc.rust-lang.org/std/marker/trait.Copy.html
 
 
Thanks, I did not know that.
Jan 07 2022
prev sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 29.12.21 06:09, Walter Bright wrote:
 On 11/9/2021 11:09 PM, Timon Gehr wrote:
 On 10/16/21 1:12 AM, Walter Bright wrote:
 On 10/12/2021 2:38 PM, Timon Gehr wrote:
 - non-lexical variable lifetimes (probably not happening)
It's already implemented for live.
Specifically, I would like it to influence scoping. ```d int x=2; int y=move(x); int z=x; // error: undefined identifier x (was moved away)
live currently does that for pointers, but not for non-pointers.
It removes the variable from the scope? (And anyway, live is a function annotation, which makes little sense.)
 What's the use case for it?
 ...
This is just how moving things works. If you move it, it's no longer where it was. If the variable disappears, we don't have to bother with putting `x` into some safe default state. Some types can't even naturally support a safe default state. The simplest example is indeed a `struct` implementing a unique non-null pointer managing its own memory. (By whatever means you want, it does not even have to have any pointer members to implement such semantics.)
 
 int y=move(y); // ok
 ```
I see what you mean, but since D disallows:     int x; { int x; } which prevents a number of bugs, so I can't see allowing that.
I don't see how that's related. It's two variables `y` whose lifetimes do not overlap. It's more like this: {int x; } { int x; } Which D allows.
Jan 03 2022
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 1/3/2022 8:30 PM, Timon Gehr wrote:
 On 29.12.21 06:09, Walter Bright wrote:
  live currently does that for pointers, but not for non-pointers.
It removes the variable from the scope? (And anyway, live is a function annotation, which makes little sense.)
live applies to all the contents of the function. `scope` is ignored for non-pointer variables, whether they are live or not.
 What's the use case for it?
 ...
This is just how moving things works. If you move it, it's no longer where it was. If the variable disappears, we don't have to bother with putting `x` into some safe default state. Some types can't even naturally support a safe default state. The simplest example is indeed a `struct` implementing a unique non-null pointer managing its own memory. (By whatever means you want, it does not even have to have any pointer members to implement such semantics.)
 int y=move(y); // ok
 ```
I see what you mean, but since D disallows:      int x; { int x; } which prevents a number of bugs, so I can't see allowing that.
I don't see how that's related. It's two variables `y` whose lifetimes do not overlap. It's more like this: {int x; } { int x; } Which D allows.
You are pedantically correct, but it's one of those things that would be disallowed because it *looks* like a bug. There's no ambiguity to int x; { int x; } either, it just *looks* like a bug, and a good chunk of the time it is not intended by the user and is a bug. I haven't seen a case yet where such code is needed. I don't see a necessity to allow the y redeclaration.
Jan 07 2022
parent Timon Gehr <timon.gehr gmx.ch> writes:
On 1/8/22 02:01, Walter Bright wrote:
 On 1/3/2022 8:30 PM, Timon Gehr wrote:
 On 29.12.21 06:09, Walter Bright wrote:
  live currently does that for pointers, but not for non-pointers.
It removes the variable from the scope? (And anyway, live is a function annotation, which makes little sense.)
live applies to all the contents of the function. ...
And none of the calling context. As I said, makes little sense.
 `scope` is ignored for non-pointer variables, whether they are  live or 
 not.
 ...
The language can't know what's designed to act like a pointer.
 
 What's the use case for it?
 ...
This is just how moving things works. If you move it, it's no longer where it was. If the variable disappears, we don't have to bother with putting `x` into some safe default state. Some types can't even naturally support a safe default state. The simplest example is indeed a `struct` implementing a unique non-null pointer managing its own memory. (By whatever means you want, it does not even have to have any pointer members to implement such semantics.)
 int y=move(y); // ok
 ```
I see what you mean, but since D disallows:      int x; { int x; } which prevents a number of bugs, so I can't see allowing that.
I don't see how that's related. It's two variables `y` whose lifetimes do not overlap. It's more like this: {int x; } { int x; } Which D allows.
You are pedantically correct, but it's one of those things that would be disallowed because it *looks* like a bug.
Perhaps that's what it looks like to you, but to other people it just looks like the typestate pattern, for example.
 There's no ambiguity to
 
      int x; { int x; }
 
 either, it just *looks* like a bug, and a good chunk of the time it is 
 not intended by the user and is a bug. I haven't seen a case yet where 
 such code is needed.
 ...
I fully agree that variable hiding is error prone, but that's just not what's going on here.
 I don't see a necessity to allow the y redeclaration.
_Redeclaring_ an _existing_ variable is of course disallowed. Declaring a variable of the same name as one that's consumed in its initializer is rather common (e.g. typestate pattern). And it is convenient and not error prone at all.
Jan 09 2022
prev sibling parent Timon Gehr <timon.gehr gmx.ch> writes:
On 16.10.21 01:12, Walter Bright wrote:
 On 10/12/2021 2:38 PM, Timon Gehr wrote:
 - non-lexical variable lifetimes (probably not happening)
It's already implemented for live.
(Also, I want it based on the types of the involved values, not based on a non-modular function annotation.)
Nov 14 2021
prev sibling next sibling parent reply Atila Neves <atila.neves gmail.com> writes:
On Tuesday, 12 October 2021 at 21:38:48 UTC, Timon Gehr wrote:
 On 10/11/21 5:59 PM, Atila Neves wrote:
 ...
This is likely to be incomplete or overly abstract, but here's my approximate take:
 * Worst features implemented in a non-toy language
- Turing-complete constructors
Care to explain?
 -  safe `void` initialization
For what types? It doesn't compile for pointers, for instance, and I don't see why void initialising an int would be unsafe.
 -  safe extern(C) function prototypes
Instead of trusted, you mean?
 - .init
Because?
 - separation of templates and CTFE
What would it look like if they weren't separated?
 - interaction of type qualifiers with reference types
I'd love to know what you mean by this.
Nov 05 2021
next sibling parent reply victoroak <jackpboy gmail.com> writes:
On Friday, 5 November 2021 at 17:02:05 UTC, Atila Neves wrote:
 -  safe `void` initialization
For what types? It doesn't compile for pointers, for instance, and I don't see why void initialising an int would be unsafe.
 - .init
Because?
Well, I can't answer for him but `void` initialization and `.init` makes it impossible to have any meaningful constraint on a type. And some types may depend on these constraints to maintain safety. ```d import std.stdio; struct LimitedInt(int min, int max) { disable this(); this(int number) { assert(number >= min); assert(number <= max); _number = number; } private int _number; } void main() safe { LimitedInt!(1, 1000) x = void; auto y = LimitedInt!(1, 1000).init; writeln(x); writeln(y); } ``` It's ` safe` in this example but there's no way to enforce these constraints when you have those.
Nov 05 2021
next sibling parent reply "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Fri, Nov 05, 2021 at 09:22:12PM +0000, victoroak via Digitalmars-d wrote:
 On Friday, 5 November 2021 at 17:02:05 UTC, Atila Neves wrote:
 
 -  safe `void` initialization
For what types? It doesn't compile for pointers, for instance, and I don't see why void initialising an int would be unsafe.
 - .init
Because?
Well, I can't answer for him but `void` initialization and `.init` makes it impossible to have any meaningful constraint on a type. And some types may depend on these constraints to maintain safety. ```d import std.stdio; struct LimitedInt(int min, int max) { disable this(); this(int number) { assert(number >= min); assert(number <= max); _number = number; } private int _number; } void main() safe { LimitedInt!(1, 1000) x = void; auto y = LimitedInt!(1, 1000).init; writeln(x); writeln(y); } ``` It's ` safe` in this example but there's no way to enforce these constraints when you have those.
safe does not mean enforcing type constraints. It means *memory* safety. The above code exhibits no memory unsafety, even though constraints are violated and the output is, ostensibly, wrong because of broken constraints. T -- There are four kinds of lies: lies, damn lies, and statistics.
Nov 05 2021
parent reply victoroak <jackpboy gmail.com> writes:
On Friday, 5 November 2021 at 21:46:35 UTC, H. S. Teoh wrote:
  safe does not mean enforcing type constraints.  It means 
 *memory* safety.  The above code exhibits no memory unsafety, 
 even though constraints are violated and the output is, 
 ostensibly, wrong because of broken constraints.
`.init` was not mentioned as breaking ` safe` just as a bad feature and I was answering why I think it is a bad feature. But the presence of both `.init` and safe `void` initialization makes it way harder to write correct ` trusted` code that depends on some constraints because you can't really enforce them.
Nov 05 2021
parent Paul Backus <snarwin gmail.com> writes:
On Friday, 5 November 2021 at 21:54:27 UTC, victoroak wrote:
 On Friday, 5 November 2021 at 21:46:35 UTC, H. S. Teoh wrote:
  safe does not mean enforcing type constraints.  It means 
 *memory* safety.  The above code exhibits no memory unsafety, 
 even though constraints are violated and the output is, 
 ostensibly, wrong because of broken constraints.
`.init` was not mentioned as breaking ` safe` just as a bad feature and I was answering why I think it is a bad feature. But the presence of both `.init` and safe `void` initialization makes it way harder to write correct ` trusted` code that depends on some constraints because you can't really enforce them.
...which is one of the reasons we need system variables: https://github.com/dlang/DIPs/blob/master/DIPs/DIP1035.md
Nov 05 2021
prev sibling parent reply Atila Neves <atila.neves gmail.com> writes:
On Friday, 5 November 2021 at 21:22:12 UTC, victoroak wrote:
 On Friday, 5 November 2021 at 17:02:05 UTC, Atila Neves wrote:
 -  safe `void` initialization
For what types? It doesn't compile for pointers, for instance, and I don't see why void initialising an int would be unsafe.
 - .init
Because?
Well, I can't answer for him but `void` initialization and `.init` makes it impossible to have any meaningful constraint on a type. And some types may depend on these constraints to maintain safety. ```d import std.stdio; struct LimitedInt(int min, int max) { disable this(); this(int number) { assert(number >= min); assert(number <= max); _number = number; } private int _number; } void main() safe { LimitedInt!(1, 1000) x = void; auto y = LimitedInt!(1, 1000).init; writeln(x); writeln(y); } ``` It's ` safe` in this example but there's no way to enforce these constraints when you have those.
Interesting. Adding an invariant causes compilation to fail: ``` foo.d(27): Error: variable `foo.main.x` `void` initializers for structs with invariants are not allowed in safe functions ```
Nov 08 2021
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 08.11.21 15:04, Atila Neves wrote:
 On Friday, 5 November 2021 at 21:22:12 UTC, victoroak wrote:
 On Friday, 5 November 2021 at 17:02:05 UTC, Atila Neves wrote:
 -  safe `void` initialization
For what types? It doesn't compile for pointers, for instance, and I don't see why void initialising an int would be unsafe.
 - .init
Because?
Well, I can't answer for him but `void` initialization and `.init` makes it impossible to have any meaningful constraint on a type. And some types may depend on these constraints to maintain safety. ```d import std.stdio; struct LimitedInt(int min, int max) {     disable this();     this(int number)     {         assert(number >= min);         assert(number <= max);         _number = number;     }     private int _number; } void main() safe {     LimitedInt!(1, 1000) x = void;     auto y = LimitedInt!(1, 1000).init;     writeln(x);     writeln(y); } ``` It's ` safe` in this example but there's no way to enforce these constraints when you have those.
Interesting. Adding an invariant causes compilation to fail: ``` foo.d(27): Error: variable `foo.main.x` `void` initializers for structs with invariants are not allowed in safe functions ```
Well, that makes some sense, but a struct can have an invariant without actually having it spelled out explicitly in the source code. Furthermore, adding contracts actually makes code less safe in -release mode.
Nov 09 2021
parent reply Atila Neves <atila.neves gmail.com> writes:
On Tuesday, 9 November 2021 at 16:37:37 UTC, Timon Gehr wrote:
 On 08.11.21 15:04, Atila Neves wrote:
 On Friday, 5 November 2021 at 21:22:12 UTC, victoroak wrote:
 [...]
Interesting. Adding an invariant causes compilation to fail: ``` foo.d(27): Error: variable `foo.main.x` `void` initializers for structs with invariants are not allowed in safe functions ```
Well, that makes some sense, but a struct can have an invariant without actually having it spelled out explicitly in the source code. Furthermore, adding contracts actually makes code less safe in -release mode.
IMHO -release mode really shouldn't be used, but since contracts are supposed to prevent bugs from occurring, hopefully testing "proved" that "none" exist. In this case specifically, even with -release one gets a compiler error, which is enough of a reason to add one methinks.
Nov 09 2021
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 09.11.21 18:13, Atila Neves wrote:
 On Tuesday, 9 November 2021 at 16:37:37 UTC, Timon Gehr wrote:
 On 08.11.21 15:04, Atila Neves wrote:
 On Friday, 5 November 2021 at 21:22:12 UTC, victoroak wrote:
 [...]
Interesting. Adding an invariant causes compilation to fail: ``` foo.d(27): Error: variable `foo.main.x` `void` initializers for structs with invariants are not allowed in safe functions ```
Well, that makes some sense, but a struct can have an invariant without actually having it spelled out explicitly in the source code. Furthermore, adding contracts actually makes code less safe in -release mode.
IMHO -release mode really shouldn't be used, but since contracts are supposed to prevent bugs from occurring, hopefully testing "proved" that "none" exist. In this case specifically, even with -release one gets a compiler error, which is enough of a reason to add one methinks.
"Add an empty invariant to your types for maximum type safety", "we have constructors, but your types have to cope with arbitrary bit patterns anyway" or "this thing is safe but some compiler backends may treat it as UB anyway" are The Last Thing D Needs.
Nov 10 2021
parent deadalnix <deadalnix gmail.com> writes:
On Thursday, 11 November 2021 at 02:20:50 UTC, Timon Gehr wrote:
 "Add an empty invariant to your types for maximum type safety", 
 "we have constructors, but your types have to cope with 
 arbitrary bit patterns anyway" or "this thing is  safe but some 
 compiler backends may treat it as UB anyway" are The Last Thing 
 D Needs.
This is unfortunately true. This is pervasive in D and by far the biggest practical problem with it.
Dec 17 2021
prev sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 11/5/21 6:02 PM, Atila Neves wrote:
 On Tuesday, 12 October 2021 at 21:38:48 UTC, Timon Gehr wrote:
 On 10/11/21 5:59 PM, Atila Neves wrote:
 ...
...
Sorry, just noticed I never answered this...
 This is likely to be incomplete or overly abstract, but here's my 
 approximate take:

 * Worst features implemented in a non-toy language
- Turing-complete constructors
Care to explain? ...
The goal of construction is to create an instance that usually should satisfy a certain invariant. (I don't necessarily mean invariant contracts, often invariants are left implicit.) Therefore, to construct an instance, all that needs to happen is input validation and moving the constructor arguments into the fields of the instance. Right now, constructors first get you some instance _that does not yet satisfy the invariant_ and basically allows you to do anything you want with it. That's quite a drag on type safety. (E.g., good luck adding non-null pointers.) ```d struct S{ immutable int x; this(int x){ foo(); this.x=1; foo(); } void foo(){ writeln(x); } } ``` There just should not be a way to obtain instances that violate (type system) invariants. I think Walter agrees that the constructor design is not optimal, especially regarding exception safety.
 -  safe `void` initialization
For what types? It doesn't compile for pointers, for instance, and I don't see why void initialising an int would be unsafe. ...
The backends may treat accessing it as UB. I'd expect both ldc and gdc to think accessing a void-initialized value is UB. The worst thing is safe void initialization for user-defined types.
 -  safe extern(C) function prototypes
Instead of trusted, you mean? ...
Yes, at least with trusted you can find it with grep. Slapping safe on something should never be dangerous.
 - .init
Because? ...
It's Hoare's billion dollar mistake, extended to all types. Having a default instance is often antithetical to strong invariants. At least it can be hidden I guess.
 - separation of templates and CTFE
What would it look like if they weren't separated? ...
Stefan's type functions come close. (But I'd like to have dependent types as well.) E.g., manipulating arrays of types in CTFE functions.
 - interaction of type qualifiers with reference types
I'd love to know what you mean by this.
The most obvious one is that there is no way to declare a tail-mutable class reference. There's also this: ```d import std.stdio; class C{ static x = [1,2,3]; this(){ x[0]=2; } this()immutable{} } void main(){ auto a=new immutable(C)(); writeln(a.x); // [1,2,3] auto b=new C(); writeln(a.x); // [2,2,3] } ```
Nov 10 2021
parent Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= <ola.fosheim.grostad gmail.com> writes:
On Thursday, 11 November 2021 at 00:26:06 UTC, Timon Gehr wrote:
 On 11/5/21 6:02 PM, Atila Neves wrote:
 On Tuesday, 12 October 2021 at 21:38:48 UTC, Timon Gehr wrote:
 - .init
Because? ...
It's Hoare's billion dollar mistake, extended to all types. Having a default instance is often antithetical to strong invariants. At least it can be hidden I guess.
I don't see how ```.init``` is related to null as long as you can disable default construction? That said, I find ```.init``` annoying and want to see it adjusted (zero default across the board for fast array initialization + user provided default constructor).
Nov 11 2021
prev sibling next sibling parent reply Dr Machine Code <jckj33 gmail.com> writes:
On Tuesday, 12 October 2021 at 21:38:48 UTC, Timon Gehr wrote:
 On 10/11/21 5:59 PM, Atila Neves wrote:
 ...
This is likely to be incomplete or overly abstract, but here's my approximate take:
 * Worst features implemented in a non-toy language
- unsound type system - undefined behavior for categories of errors other than memory corruption - inappropriately nondeterministic semantics - mutable aliasing by default (mutability is fine, aliasing is the issue) - pointer arithmetic without appropriate type system support - imprecise type system (>40 years behind state of the art) - non-orthogonal language definition - null pointers without appropriate type system support - Turing-complete constructors
 * Worst features (in your opinion) in D
- undefined behavior for categories of errors other than memory corruption, e.g. 'assert' - safe `void` initialization - safe extern(C) function prototypes - inout - nondeterministic floating-point semantics - forward reference errors/ambiguities (arising from underspecification of compile-time introspection) - .init - separation of templates and CTFE - null pointers - Turing-complete constructors - Object - interaction of type qualifiers with reference types - underspecification of type/function qualifiers - template syntax is inconsistent between declaration and call site - alias this (it uses lookup rules different from import) - slicing and indexing of sequences is magic, there is no way to slice a library tuple without decaying into an auto-expanding sequence
 * Features you'd like to see in D
- built-in tuples/products with standard syntax - built-in tagged unions/sums, nullable, algebraic data types - pattern matching - real support for linear/affine typing - named parameters with support for perfect forwarding and compile-time introspection - built-in duck-typed record types playing nice with named parameters - type classes / some standard way to add UFCS methods to a type from another module that are then visible in an instantiated template from a third module - uniform syntax for function definition, in particular `int add(int a,int b)=>a+b;` (-preview=shortenedMethods) - `let Statement in Expression` expression - `Expression where Statement` expression
could you give example what those would be like?
 - mixin identifiers
example?
 - __local, static break and continue
what would __local do?
 (https://github.com/dlang/DIPs/blob/master/DIPs/accepted/DIP1010.md)
 - template literals
example?
 - static opIndex/opSlice
 - AST introspection
 - consistent treatment of operators for built-in types, e.g. 
 1.opBinary!"+"(2) should work.
 - operator overloading should combine orthogonally with UFCS
 - better support for subtyping (expose the concept to 
 user-defined types, e.g., Range!(const(T)) could be a subtype 
 of const(Range!T)) and any other features required to support a 
 good container library
 - async/await (or similar)
 - yield (or similar)
 - range literals
what's that?
 - more lightweight coroutines
 - ProtoObject
 - special treatment of qualified types, in particular qualified 
 reference types (e.g. `immutable` classes should allow 
 conversion of references from `immutable` to mutable)
 - non-deterministic semantics, with as little undefined 
 behavior as possible, in particular for type/function qualifiers
 - compile-time fixed-point support (e.g., with struct S(T){ T* 
 next; }, fix!S gives a singly linked list).
 - flow-sensitive typing
what's that?
 - strong variable updates (probably not happening)
what's that?
 - non-lexical variable lifetimes (probably not happening)
 - parametric polymorphism, in particular for type qualifiers 
 (probably not happening)
 - some amount of dependent types (dreaming now)
you got very nice features, are you making DIPs for those?
Nov 14 2021
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 14.11.21 22:54, Dr Machine Code wrote:
 On Tuesday, 12 October 2021 at 21:38:48 UTC, Timon Gehr wrote:
 On 10/11/21 5:59 PM, Atila Neves wrote:
 ...
...
 * Features you'd like to see in D
- built-in tuples/products with standard syntax
auto (a,b) = (1,2); (int a, string b) = fetch!((x)=>(1,text(x))); [(1,2),(3,4)].map!((a,b)=>a+b).each!writeln;
 - built-in tagged unions/sums,
Not sure about detailed syntax, maybe something like: (int+string) x = inj(0,1); (int+string) y = inj(1,"hi");
 nullable,
Maybe: int*? x=null; writeln(*x); // error if(x) writeln(*x); // ok C? x = ...; D? = x?.method();
 algebraic data types
Maybe: enum Result(T){ Ok(T), Error(string) }
 - pattern matching
auto x = match(r){ Ok(0) => 3; Ok(x) => x+1; Error(_): assert(0); } int toInt((int+string) x) match(x){ (0, x): return x; (1, s): return to!int(s); } }
 - real support for linear/affine typing
auto x = S(); auto y = move(x); auto z = x; // error: undefined identifier x auto y = move(y); // ok // error: y was not explicitly moved away or destroyed
 - named parameters with support for perfect forwarding and 
 compile-time introspection
void foo(int x=0,int y=0,int z=0; foo(x: 100, z: 200); auto apply(alias f,T...)(T args){ return f(args); } apply!foo(x: 100, z: 200);
 - built-in duck-typed record types playing nice with named parameters
auto r = (x: 100, z: 200); foo(r);
 - type classes / some standard way to add UFCS methods to a type from 
 another module that are then visible in an instantiated template from 
 a third module
import a: S; import b: rangeFun; auto ref front(ref S s){ ... } bool empty(ref S s){ ... } void popFront(){ ... } void main(){ S s; rangeFun(s with(front, empty, popFront)); alias T=S with (front,empty,popFront); T t=s; rangeFun(t); }
 - uniform syntax for function definition, in particular `int add(int 
 a,int b)=>a+b;` (-preview=shortenedMethods)
int add(int a,int b)=>a+b;
 - `let Statement in Expression` expression
void main(){ auto z = { int x=1; int y=2; } in x+y; assert(z==3); }
 - `Expression where Statement` expression
...
void main(){ auto z = x+y where{ int x=1; int y=2; }; assert(z==3); }
 could you give example what those would be like?
 ...
See above. Unfortunately I only had time to give some contrived examples.
 - mixin identifiers
example?
static foreach((name, value);[("x",1),("y",2),("z",3)]){ int mixin(name) = value; } writeln(x," ",y," ",z); // 1 2 3
 - __local, static break and continue
what would __local do? ...
static foreach(i;0..100){ __local alias X=Foo!(T[i]); // local to static foreach, does not clash between iterations mixin Bar!X; }
 (https://github.com/dlang/DIPs/blob/master/DIPs/accepted/DIP1010.md)
Also see the explanation in the DIP.
 - template literals
example?
enum sizes = staticMap!((B)!=>B.sizeof,Types);
 - static opIndex/opSlice
 - AST introspection
 - consistent treatment of operators for built-in types, e.g. 
 1.opBinary!"+"(2) should work.
 - operator overloading should combine orthogonally with UFCS
 - better support for subtyping (expose the concept to user-defined 
 types, e.g., Range!(const(T)) could be a subtype of const(Range!T)) 
 and any other features required to support a good container library
 - async/await (or similar)
 - yield (or similar)
 - range literals
what's that?
auto b = (fun(x) for x in iota(100) if bar(x)); // equivalent to: // auto b = iota(100).filter!(x=>bar(x)).map!(x=>fun(x));
 - more lightweight coroutines
 - ProtoObject
 - special treatment of qualified types, in particular qualified 
 reference types (e.g. `immutable` classes should allow conversion of 
 references from `immutable` to mutable)
 - non-deterministic semantics, with as little undefined behavior as 
 possible, in particular for type/function qualifiers
 - compile-time fixed-point support (e.g., with struct S(T){ T* next; 
 }, fix!S gives a singly linked list).
 - flow-sensitive typing
what's that?
class A{ void foo(){ ... } } class B:A{ void bar(){ ... } } void foo(A a){ if(a is B){ B b=a; // ok a.bar(); // ok } }
 - strong variable updates (probably not happening)
what's that?
int x=2; x="123"; static assert(is(typeof(x)==string)); auto f=File(x,"r"); static assert(is(typeof(f)==File)); f.close(); static assert(is(typeof(f)==ClosedFile));
 - non-lexical variable lifetimes (probably not happening)
 - parametric polymorphism, in particular for type qualifiers (probably 
 not happening)
 - some amount of dependent types (dreaming now)
you got very nice features, are you making DIPs for those?
I started this: https://github.com/tgehr/DIPs/blob/tuple-syntax/DIPs/DIP1xxx-tg.md https://github.com/tgehr/dmd/commits/tuple-syntax Unfortunately, I was too busy at the time to finish the implementation, and I am not fully satisfied with the proposal. Probably I'd want to add at least static opIndex and static opSlice to it. Another issue is that it slightly expands `alias this` and I am not sure whether that's a direction Walter is willing to invest in at this point.
Nov 14 2021
next sibling parent reply Arjan <arjan ask.me.to> writes:
On Sunday, 14 November 2021 at 23:05:03 UTC, Timon Gehr wrote:
 On 14.11.21 22:54, Dr Machine Code wrote:
 On Tuesday, 12 October 2021 at 21:38:48 UTC, Timon Gehr wrote:
 On 10/11/21 5:59 PM, Atila Neves wrote:
 ...
...
 * Features you'd like to see in D
- built-in tuples/products with standard syntax
...
 I started this:
 https://github.com/tgehr/DIPs/blob/tuple-syntax/DIPs/DIP1xxx-tg.md
 https://github.com/tgehr/dmd/commits/tuple-syntax

 Unfortunately, I was too busy at the time to finish the 
 implementation, and I am not fully satisfied with the proposal. 
 Probably I'd want to add at least static opIndex and static 
 opSlice to it. Another issue is that it slightly expands `alias 
 this` and I am not sure whether that's a direction Walter is 
 willing to invest in at this point.
Just WOW. What would be needed to get you working on this again?
Nov 15 2021
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 15.11.21 09:01, Arjan wrote:
 
 I started this:
 https://github.com/tgehr/DIPs/blob/tuple-syntax/DIPs/DIP1xxx-tg.md
 https://github.com/tgehr/dmd/commits/tuple-syntax

 Unfortunately, I was too busy at the time to finish the 
 implementation, and I am not fully satisfied with the proposal. 
 Probably I'd want to add at least static opIndex and static opSlice to 
 it. Another issue is that it slightly expands `alias this` and I am 
 not sure whether that's a direction Walter is willing to invest in at 
 this point.
Just WOW. What would be needed to get you working on this again?
Some reassurance that it won't be shot down for stupid reasons would go a long way. For `static foreach`, the desired semantics were clear to Walter and Andrei from the start and they really wanted that feature in DMD, so that the DIP process went pretty smoothly. I am not feeling any similar excitement for tuples, even though it's the most wanted feature among forum readers according to the state of D 2018 survey... I just don't have the time and energy required for week-long forum debates anymore.
Nov 15 2021
next sibling parent Patrick Schluter <Patrick.Schluter bbox.fr> writes:
On Tuesday, 16 November 2021 at 02:14:22 UTC, Timon Gehr wrote:
 On 15.11.21 09:01, Arjan wrote:
 
 I started this:
 https://github.com/tgehr/DIPs/blob/tuple-syntax/DIPs/DIP1xxx-tg.md
 https://github.com/tgehr/dmd/commits/tuple-syntax

 Unfortunately, I was too busy at the time to finish the 
 implementation, and I am not fully satisfied with the 
 proposal. Probably I'd want to add at least static opIndex 
 and static opSlice to it. Another issue is that it slightly 
 expands `alias this` and I am not sure whether that's a 
 direction Walter is willing to invest in at this point.
Just WOW. What would be needed to get you working on this again?
Some reassurance that it won't be shot down for stupid reasons would go a long way. For `static foreach`, the desired semantics were clear to Walter and Andrei from the start and they really wanted that feature in DMD, so that the DIP process went pretty smoothly. I am not feeling any similar excitement for tuples, even though it's the most wanted feature among forum readers according to the state of D 2018 survey... I just don't have the time and energy required for week-long forum debates anymore.
The proposition at that time was stalled because it collided with the comma expression and it was convened that the comma operator would have to be removed before tuple syntax could be introduced. Now that comma operator is deprecated, it would be the right time to reintroduce the tuple syntax.
Nov 17 2021
prev sibling next sibling parent reply Atila Neves <atila.neves gmail.com> writes:
On Tuesday, 16 November 2021 at 02:14:22 UTC, Timon Gehr wrote:
 On 15.11.21 09:01, Arjan wrote:
 
 [...]
Just WOW. What would be needed to get you working on this again?
Some reassurance that it won't be shot down for stupid reasons would go a long way. For `static foreach`, the desired semantics were clear to Walter and Andrei from the start and they really wanted that feature in DMD, so that the DIP process went pretty smoothly. I am not feeling any similar excitement for tuples, even though it's the most wanted feature among forum readers according to the state of D 2018 survey... I just don't have the time and energy required for week-long forum debates anymore.
I don't see any good reason to shut it down, never mind stupid reasons.
Nov 23 2021
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 23.11.21 14:41, Atila Neves wrote:
 On Tuesday, 16 November 2021 at 02:14:22 UTC, Timon Gehr wrote:
 On 15.11.21 09:01, Arjan wrote:
 [...]
Just WOW. What would be needed to get you working on this again?
Some reassurance that it won't be shot down for stupid reasons would go a long way. For `static foreach`, the desired semantics were clear to Walter and Andrei from the start and they really wanted that feature in DMD, so that the DIP process went pretty smoothly. I am not feeling any similar excitement for tuples, even though it's the most wanted feature among forum readers according to the state of D 2018 survey... I just don't have the time and energy required for week-long forum debates anymore.
I don't see any good reason to shut it down, never mind stupid reasons.
There are some details such as ABI and sizeof(()). I'll probably get back to this by January. (Some other commitments will have ended by then.)
Nov 23 2021
parent Arjan <arjan ask.me.to> writes:
On Wednesday, 24 November 2021 at 05:29:54 UTC, Timon Gehr wrote:
 On 23.11.21 14:41, Atila Neves wrote:
 On Tuesday, 16 November 2021 at 02:14:22 UTC, Timon Gehr wrote:
 [...]
I don't see any good reason to shut it down, never mind stupid reasons.
There are some details such as ABI and sizeof(()). I'll probably get back to this by January. (Some other commitments will have ended by then.)
That will be highly appreciated. Is there anything we could do to help you? Can I buy you a coffee/pizza/beer/scotch/.. ?
Nov 24 2021
prev sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 11/15/2021 6:14 PM, Timon Gehr wrote:
 Some reassurance that it won't be shot down for stupid reasons would go a long 
 way. For `static foreach`, the desired semantics were clear to Walter and
Andrei 
 from the start and they really wanted that feature in DMD, so that the DIP 
 process went pretty smoothly. I am not feeling any similar excitement for 
 tuples, even though it's the most wanted feature among forum readers according 
 to the state of D 2018 survey... I just don't have the time and energy
required 
 for week-long forum debates anymore.
Actually, I agree with the need for tuples, and am very open to a good design for it.
Dec 28 2021
next sibling parent Tejas <notrealemail gmail.com> writes:
On Wednesday, 29 December 2021 at 05:14:43 UTC, Walter Bright 
wrote:
 On 11/15/2021 6:14 PM, Timon Gehr wrote:
 Some reassurance that it won't be shot down for stupid reasons 
 would go a long way. For `static foreach`, the desired 
 semantics were clear to Walter and Andrei from the start and 
 they really wanted that feature in DMD, so that the DIP 
 process went pretty smoothly. I am not feeling any similar 
 excitement for tuples, even though it's the most wanted 
 feature among forum readers according to the state of D 2018 
 survey... I just don't have the time and energy required for 
 week-long forum debates anymore.
Actually, I agree with the need for tuples, and am very open to a good design for it.
Sorry if this sounds very naive, but if we can't use the `struct` ABI for tuples, why don't we use the `class` ABI? Yeah, reference types are undesirable, but it sounds like a very viable placeholder until we think of a better implementation.
Dec 28 2021
prev sibling next sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 12/28/2021 9:14 PM, Walter Bright wrote:
 Actually, I agree with the need for tuples, and am very open to a good design 
 for it.
I'd like to see something that unified arrays, structs, argument lists (for functions).
Dec 28 2021
next sibling parent Dukc <ajieskola gmail.com> writes:
On Wednesday, 29 December 2021 at 06:48:11 UTC, Walter Bright 
wrote:
 On 12/28/2021 9:14 PM, Walter Bright wrote:
 Actually, I agree with the need for tuples, and am very open 
 to a good design for it.
I'd like to see something that unified arrays, structs, argument lists (for functions).
I think we should unify static arrays and tuples, and call it a day. A tuple or a static array still would not be the same as an argument list, but could be easily converted to one with `.expand`, just like the present-day tuple. As for `struct`s, I think it's better they're not interchangeable with other types by default. One reason is that we still want that overloads like this are possible: ```d void setBackgroundColour(RGB colour); void setBackgroundColour(HSV colour); ``` This way, the author of a type can decide whether the type should be interchangeable: ```d // not interchangeable with other types of similar structure struct Vector(size_t dim) { private float[dim] content; ref opIndex(size_t i){return content[i];} } // This would be interchangeable alias Vector(size_t dim) = float[dim]; // Also interchangeable alias Vector(size_t dim) = Tuple!(Repeat!(dim, float)); ``` Also, If we accept https://github.com/dlang/DIPs/pull/173 (I definitely like it!), I suggest that we also make `void` the same type as `Tuple!()` and `AnyType[0]`.
Dec 29 2021
prev sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 12/29/21 7:48 AM, Walter Bright wrote:
 On 12/28/2021 9:14 PM, Walter Bright wrote:
 Actually, I agree with the need for tuples, and am very open to a good 
 design for it.
I'd like to see something that unified arrays, structs, argument lists (for functions).
I would like to do that, but I think it would break code like this: void foo(int a,int b){} void foo(int[2] x){} After unification, those two function definitions would now be the same. Is this what you have in mind?
Jan 02 2022
next sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 1/3/22 8:40 AM, Timon Gehr wrote:
 On 12/29/21 7:48 AM, Walter Bright wrote:
 On 12/28/2021 9:14 PM, Walter Bright wrote:
 Actually, I agree with the need for tuples, and am very open to a 
 good design for it.
I'd like to see something that unified arrays, structs, argument lists (for functions).
I would like to do that, but I think it would break code like this: void foo(int a,int b){} void foo(int[2] x){} After unification, those two function definitions would now be the same. Is this what you have in mind?
And there is also this: void foo(T...)(T args){} int[2] x; foo(x); // foo!(int[2]) and foo!(int,int) would now need to be the same
Jan 02 2022
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 1/2/2022 11:42 PM, Timon Gehr wrote:
 And there is also this:
 
 void foo(T...)(T args){}
 
 int[2] x;
 
 foo(x); // foo!(int[2]) and foo!(int,int) would now need to be the same
With such implicit conversions, the language would just descend into chaos. So no :-)
Jan 03 2022
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 03.01.22 10:27, Walter Bright wrote:
 On 1/2/2022 11:42 PM, Timon Gehr wrote:
 And there is also this:

 void foo(T...)(T args){}

 int[2] x;

 foo(x); // foo!(int[2]) and foo!(int,int) would now need to be the same
With such implicit conversions, the language would just descend into chaos. So no :-)
It's not an implicit conversion. I am mostly trying to figure out what constitutes "unification" for you. (In the programming languages I built, `int×int` and `int^2` are literally the same type, there is subtyping, but all actual type conversions are explicit.) Personally, the single thing I care most about in terms of "unification" is that this works: void foo(int a,int b){} (int,int) t; foo(t); // ok, function expects (int,int), and (int,int) was given But *not* this: void foo((int,int) a,int b){} (int,int,int) t; foo(t); // error, function expects ((int,int),int), not (int,int,int) I do not care much about `is((int,int)==int[2])`, but when you say you want to unify tuples and static arrays, that's what I think of.
Jan 03 2022
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 1/3/2022 6:06 PM, Timon Gehr wrote:
 On 03.01.22 10:27, Walter Bright wrote:
 On 1/2/2022 11:42 PM, Timon Gehr wrote:
 And there is also this:

 void foo(T...)(T args){}

 int[2] x;

 foo(x); // foo!(int[2]) and foo!(int,int) would now need to be the same
With such implicit conversions, the language would just descend into chaos. So no :-)
It's not an implicit conversion.
Looks like it to me!
 I am mostly trying to figure out what 
 constitutes "unification" for you. (In the programming languages I built, 
 `int×int` and `int^2` are literally the same type, there is subtyping, but
all 
 actual type conversions are explicit.)
 
 Personally, the single thing I care most about in terms of "unification" is
that 
 this works:
 
 void foo(int a,int b){}
 (int,int) t;
 foo(t); // ok, function expects (int,int), and (int,int) was given
 
 But *not* this:
 
 void foo((int,int) a,int b){}
 
 (int,int,int) t;
 foo(t); // error, function expects ((int,int),int), not (int,int,int)
 
 I do not care much about `is((int,int)==int[2])`, but when you say you want to 
 unify tuples and static arrays, that's what I think of.
That isn't what I meant. I mean that there are easy ways to convert from one to the other, but not implicit conversions.
Jan 03 2022
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 04.01.22 06:40, Walter Bright wrote:
 On 1/3/2022 6:06 PM, Timon Gehr wrote:
 On 03.01.22 10:27, Walter Bright wrote:
 On 1/2/2022 11:42 PM, Timon Gehr wrote:
 And there is also this:

 void foo(T...)(T args){}

 int[2] x;

 foo(x); // foo!(int[2]) and foo!(int,int) would now need to be the same
With such implicit conversions, the language would just descend into chaos. So no :-)
It's not an implicit conversion.
Looks like it to me! ...
If `foo(int, int)` is defined to be literally the same as `foo(int[2])`, there is no conversion. But anyway, I guess you'd also consider anything that would make this work an "implicit conversion"? double foo(int x,string y); writeln([(1,"2"),(1,"3"),(3,"4")].map!foo); If so, maybe one way to make _some_ progress on this is to have a DIP specifically for destructuring, without adding any new types?
Jan 03 2022
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 1/3/2022 10:37 PM, Timon Gehr wrote:
 If `foo(int, int)` is defined to be literally the same as `foo(int[2])`, there 
 is no conversion. But anyway, I guess you'd also consider anything that would 
 make this work an "implicit conversion"?
 
 double foo(int x,string y);
 
 writeln([(1,"2"),(1,"3"),(3,"4")].map!foo);
Currently, tuples can map right on to argument lists, there is no conversion. This works because a tuple in D isn't really a type at all. It's just a collection of expressions.
 If so, maybe one way to make _some_ progress on this is to have a DIP 
 specifically for destructuring, without adding any new types?
I'm not sure what destructuring, but yes, not adding new types.
Jan 03 2022
next sibling parent reply Paul Backus <snarwin gmail.com> writes:
On Tuesday, 4 January 2022 at 07:52:00 UTC, Walter Bright wrote:
 If so, maybe one way to make _some_ progress on this is to 
 have a DIP specifically for destructuring, without adding any 
 new types?
I'm not sure what destructuring, but yes, not adding new types.
"Destructuring" means binding members of a tuple to separate variables; e.g., struct S { int x; string y; } auto (x, y) = S(123, "hello").tupleof; assert(x == 123 && y == "hello"); C++17 has something similar, which it calls "structured bindings": https://en.cppreference.com/w/cpp/language/structured_binding
Jan 04 2022
parent Walter Bright <newshound2 digitalmars.com> writes:
Thanks, I know what that was, I just didn't know the jargon for it.
Jan 07 2022
prev sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 04.01.22 08:52, Walter Bright wrote:
 On 1/3/2022 10:37 PM, Timon Gehr wrote:
 If `foo(int, int)` is defined to be literally the same as 
 `foo(int[2])`, there is no conversion. But anyway, I guess you'd also 
 consider anything that would make this work an "implicit conversion"?

 double foo(int x,string y);

 writeln([(1,"2"),(1,"3"),(3,"4")].map!foo);
Currently, tuples can map right on to argument lists, there is no conversion. This works because a tuple in D isn't really a type at all. It's just a collection of expressions. ...
But in the example above, those so-called "tuples" would expand right into the array literal and cause an error due to incompatible types. This can't work if `(1,"2")` etc. auto-expand. Furthermore, to put them into an array, they need to have an address.
 
 If so, maybe one way to make _some_ progress on this is to have a DIP 
 specifically for destructuring, without adding any new types?
I'm not sure what destructuring,
Currently working with tuples (including actual tuples that are actual expressions, e.g., Phobos tuples) is inconvenient mostly (but not only) because you can't easily expand them into multiple named variables. ```d auto (col1, col2) = table.query!((ref row)=>tuple(row.column1,row.column2))(key); ``` Proposal 1 here: https://github.com/tgehr/DIPs/blob/tuple-syntax/DIPs/DIP1xxx-tg.md Proof-of-concept implementation here: https://github.com/tgehr/dmd/commit/8ad53b0891d3353dd96711595c06326ac0195d1b https://github.com/tgehr/dmd/commit/a0f59f93ab3727c93585dc658444860926a4b2c6
 but yes, not adding new types.
That's what I thought, so the tuple DIP is based on lowering to structs. What's the path forward to making this work? ```d double foo(int x,string y); writeln([(1,"2"),(1,"3"),(3,"4")].map!foo); ``` My suggestion was proposal 2 here: https://github.com/tgehr/DIPs/blob/tuple-syntax/DIPs/DIP1xxx-tg.md Proof-of-concept implementation here: https://github.com/tgehr/dmd/commit/bdb40fa96c471a7ace84596511a27ba3e803214f https://github.com/tgehr/dmd/commit/dad942117d85683e6234ef312c6d59be82f0c3a2 Note that Phobos tuples are implemented using an `alias this` to a built-in "tuple" of members: https://github.com/dlang/phobos/blob/master/std/typecons.d#L636-L655
Jan 04 2022
next sibling parent Walter Bright <newshound2 digitalmars.com> writes:
On 1/4/2022 3:36 PM, Timon Gehr wrote:
 On 04.01.22 08:52, Walter Bright wrote:
 On 1/3/2022 10:37 PM, Timon Gehr wrote:
 If `foo(int, int)` is defined to be literally the same as `foo(int[2])`, 
 there is no conversion. But anyway, I guess you'd also consider anything that 
 would make this work an "implicit conversion"?

 double foo(int x,string y);

 writeln([(1,"2"),(1,"3"),(3,"4")].map!foo);
Currently, tuples can map right on to argument lists, there is no conversion. This works because a tuple in D isn't really a type at all. It's just a collection of expressions. ...
But in the example above, those so-called "tuples" would expand right into the array literal and cause an error due to incompatible types. This can't work if `(1,"2")` etc. auto-expand. Furthermore, to put them into an array, they need to have an address.
I know. It's a problem.
 If so, maybe one way to make _some_ progress on this is to have a DIP 
 specifically for destructuring, without adding any new types?
I'm not sure what destructuring,
Currently working with tuples (including actual tuples that are actual expressions, e.g., Phobos tuples) is inconvenient mostly (but not only) because you can't easily expand them into multiple named variables. ```d auto (col1, col2) = table.query!((ref row)=>tuple(row.column1,row.column2))(key); ``` Proposal 1 here: https://github.com/tgehr/DIPs/blob/tuple-syntax/DIPs/DIP1xxx-tg.md Proof-of-concept implementation here: https://github.com/tgehr/dmd/commit/8ad53b0891d3353dd96711595c06326ac0195d1b https://github.com/tgehr/dmd/commit/a0f59f93ab3727c93585dc658444860926a4b2c6
 but yes, not adding new types.
That's what I thought, so the tuple DIP is based on lowering to structs. What's the path forward to making this work?
I don't know. I'll have to look at your proposals.
 
 ```d
 double foo(int x,string y);
 
 writeln([(1,"2"),(1,"3"),(3,"4")].map!foo);
 ```
 
 My suggestion was proposal 2 here:
 https://github.com/tgehr/DIPs/blob/tuple-syntax/DIPs/DIP1xxx-tg.md
 
 Proof-of-concept implementation here:
 https://github.com/tgehr/dmd/commit/bdb40fa96c471a7ace84596511a27ba3e803214f
 https://github.com/tgehr/dmd/commit/dad942117d85683e6234ef312c6d59be82f0c3a2
 
 Note that Phobos tuples are implemented using an `alias this` to a built-in 
 "tuple" of members:
 https://github.com/dlang/phobos/blob/master/std/typecons.d#L636-L655
Jan 07 2022
prev sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
I'm concerned about what would happen to the following.

All these are considered equivalent currently:

(a,b,c)
(a,(b,c))
((a,b,c))
((a,b),(c))
((a),(b),(c))

[Of course, using the __tuple syntax.]

Does your proposal change that? I can't quite be sure.
Jan 07 2022
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 1/8/22 02:39, Walter Bright wrote:
 I'm concerned about what would happen to the following.
 
 All these are considered equivalent currently:
 
 (a,b,c)
 (a,(b,c))
 ((a,b,c))
 ((a,b),(c))
 ((a),(b),(c))
 ...
x is equivalent to (x). (Always, and a design that changes that is broken.) Therefore, `(a,b,c)`, `((a,b,c))` and `((a),(b),(c))` are the same, a triple with components a, b, and c.
 [Of course, using the __tuple syntax.]
 
 Does your proposal change that? I can't quite be sure.
`(a,(b,c))` is not the same as `((a,b),c)` in my proposals, those are always pairs, where the second and first component, respectively, are also pairs. Both are distinct from `(a,b,c)`, which is always a triple. However, I don't propose to _change_ any existing auto-expanding behavior, I want to add tuple syntax and actual tuple behavior for something similar to a Phobos tuple. (I.e., based on a `struct` template.)
Jan 09 2022
parent Timon Gehr <timon.gehr gmx.ch> writes:
On 1/9/22 11:05, Timon Gehr wrote:
 
 `(a,(b,c))` is not the same as `((a,b),c)` in my proposals, those are 
 always pairs, where the second and first component, respectively, are 
 also pairs. Both are distinct from `(a,b,c)`, which is always a triple.
(Technically, I guess if `a, b or c` is an expression/expanded tuple of the variety that DMD already supports, the number of components of the results can be different.)
Jan 09 2022
prev sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 1/2/2022 11:40 PM, Timon Gehr wrote:
 On 12/29/21 7:48 AM, Walter Bright wrote:
 On 12/28/2021 9:14 PM, Walter Bright wrote:
 Actually, I agree with the need for tuples, and am very open to a good design 
 for it.
I'd like to see something that unified arrays, structs, argument lists (for functions).
I would like to do that, but I think it would break code like this: void foo(int a,int b){} void foo(int[2] x){} After unification, those two function definitions would now be the same. Is this what you have in mind?
Not exactly, since the ABI won't permit it. For example, struct S { byte b; int c; } byte b; int c; void func(byte, int); I can't call func with S(b,c); because of the function call ABI. Having a struct implicitly convertible to a tuple will also likely cause overloading confusion and will break legacy code. But we could support conversions. For example, a tuple could be converted to an anonymous struct with the syntax `struct(b,c)`. (A tuple can already be used to package up arguments to a function parameter list.) The ABI has no way to return a tuple from a function. But a function returning a tuple can be done by packing it into an anonymous struct and then unpacking it at the call site. This can happen under the hood, the user just sees a tuple. So, no, implicit conversions of Array <=> Struct <=> Tuple will likely cause many problems. But explicit conversions should work.
Jan 03 2022
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 03.01.22 10:08, Walter Bright wrote:
 On 1/2/2022 11:40 PM, Timon Gehr wrote:
 On 12/29/21 7:48 AM, Walter Bright wrote:
 On 12/28/2021 9:14 PM, Walter Bright wrote:
 Actually, I agree with the need for tuples, and am very open to a 
 good design for it.
I'd like to see something that unified arrays, structs, argument lists (for functions).
I would like to do that, but I think it would break code like this: void foo(int a,int b){} void foo(int[2] x){} After unification, those two function definitions would now be the same. Is this what you have in mind?
Not exactly, since the ABI won't permit it. For example,     struct S { byte b; int c; }     byte b;     int c;     void func(byte, int); I can't call func with S(b,c); because of the function call ABI. ...
My DIP draft extends "alias this" to allow this (which should work anyway): alias Seq(T...)=T; struct S{ byte b; int c; alias this=Seq!(b,c); } void func(byte,int); func(S()); Then it proposes to make tuples a struct template with such an alias this. Of course, it would also be possible to make tuples a built-in type, which would be my preferred design for a new language.
 Having a struct implicitly convertible to a tuple will also likely cause 
 overloading confusion and will break legacy code.
Yes, I don't want that. The benefit of introducing tuples as a struct template is precisely that it is a lot less likely to cause confusion in legacy code. It does have some significant drawbacks, e.g. `foo(int,int)` and `foo((int,int))` would have a different ABI and the second overload can't be called as `foo(1,2);`...
 But we could support conversions. For example, a tuple could be 
 converted to an anonymous struct with the syntax `struct(b,c)`. (A tuple 
 can already be used to package up arguments to a function parameter list.)
 
 The ABI has no way to return a tuple from a function. But a function 
 returning a tuple can be done by packing it into an anonymous struct and 
 then unpacking it at the call site. This can happen under the hood, the 
 user just sees a tuple.
 ...
Returning expanded values from functions is interesting (and my compiler frontend allows it), but I don't think that's really the main issue here.
 So, no, implicit conversions of Array <=> Struct <=> Tuple will likely 
 cause many problems. But explicit conversions should work.
To be very clear, I want this: [(1,2),(3,4)].map!((a,b)=>a+b).each!writeln; An this is generally what people mean when they talk about "tuples".
Jan 03 2022
next sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 04.01.22 04:09, Timon Gehr wrote:
 
 To be very clear, I want this:
 
 [(1,2),(3,4)].map!((a,b)=>a+b).each!writeln;
 
 An this is generally what people mean when they talk about "tuples".
(I understand that there is something in the DMD source code already named "Tuple", but that's not really a tuple, it's a sequence of values that will auto expand into any context. Being able to return that from functions would be nice, but I think it's independent of what people are talking about when they want tuples.)
Jan 03 2022
next sibling parent reply rikki cattermole <rikki cattermole.co.nz> writes:
On 04/01/2022 4:11 PM, Timon Gehr wrote:
 (I understand that there is something in the DMD source code already 
 named "Tuple", but that's not really a tuple, it's a sequence of values 
 that will auto expand into any context. Being able to return that from 
 functions would be nice, but I think it's independent of what people are 
 talking about when they want tuples.)
Actually this is kinda what I want. Remove array, AA definitions in syntax. All you have is a tuple. A tuple accepts both named and unnamed types or values. It can devolve into static arrays, associative arrays, dynamic arrays all implicitly.
Jan 03 2022
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 04.01.22 05:20, rikki cattermole wrote:
 
 On 04/01/2022 4:11 PM, Timon Gehr wrote:
 (I understand that there is something in the DMD source code already 
 named "Tuple", but that's not really a tuple, it's a sequence of 
 values that will auto expand into any context. Being able to return 
 that from functions would be nice, but I think it's independent of 
 what people are talking about when they want tuples.)
Actually this is kinda what I want. Remove array, AA definitions in syntax. All you have is a tuple. A tuple accepts both named and unnamed types or values. It can devolve into static arrays, associative arrays, dynamic arrays all implicitly.
My point was not that you don't want this, it was that calling it a "tuple" serves only to confuse.
Jan 03 2022
parent Timon Gehr <timon.gehr gmx.ch> writes:
On 04.01.22 06:14, Timon Gehr wrote:
 On 04.01.22 05:20, rikki cattermole wrote:
 On 04/01/2022 4:11 PM, Timon Gehr wrote:
 (I understand that there is something in the DMD source code already 
 named "Tuple", but that's not really a tuple, it's a sequence of 
 values that will auto expand into any context. Being able to return 
 that from functions would be nice, but I think it's independent of 
 what people are talking about when they want tuples.)
Actually this is kinda what I want. Remove array, AA definitions in syntax. All you have is a tuple. A tuple accepts both named and unnamed types or values. It can devolve into static arrays, associative arrays, dynamic arrays all implicitly.
My point was not that you don't want this, it was that calling it a "tuple" serves only to confuse.
(Also, having only the expanding variety of this is just not very useful as it prevents nesting.)
Jan 03 2022
prev sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 1/3/2022 7:11 PM, Timon Gehr wrote:
 On 04.01.22 04:09, Timon Gehr wrote:
 To be very clear, I want this:

 [(1,2),(3,4)].map!((a,b)=>a+b).each!writeln;

 An this is generally what people mean when they talk about "tuples".
(I understand that there is something in the DMD source code already named "Tuple", but that's not really a tuple, it's a sequence of values that will auto expand into any context. Being able to return that from functions would be nice, but I think it's independent of what people are talking about when they want tuples.)
Yes, and reconciling this will be the problem.
Jan 08 2022
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 1/9/22 00:03, Walter Bright wrote:
 On 1/3/2022 7:11 PM, Timon Gehr wrote:
 On 04.01.22 04:09, Timon Gehr wrote:
 To be very clear, I want this:

 [(1,2),(3,4)].map!((a,b)=>a+b).each!writeln;

 An this is generally what people mean when they talk about "tuples".
(I understand that there is something in the DMD source code already named "Tuple", but that's not really a tuple, it's a sequence of values that will auto expand into any context. Being able to return that from functions would be nice, but I think it's independent of what people are talking about when they want tuples.)
Yes, and reconciling this will be the problem.
I agree. This is what I had in mind: - "tuple": the new thing, has an address - "expanded tuple": the existing thing If you have a tuple `t`, you can get an expanded tuple using `t.expand`, to transform an expanded tuple `e` into a tuple, you use `(e,)`. (This is a single-element tuple, this syntax is the same as in e.g. Python. Due to auto-expanding of `e`, it can have more than one element.) In practice, I think expanding is useful, but I'd mostly prefer to use tuples that don't auto-expand and expand them explicitly with `t.expand` if needed. `t.expand` itself is of course an auto-expanding expression. In `void foo(T...)(T args)`, `args` would probably still be an expanded tuple. The main challenge is this: ```d void foo(T)(T arg){} ``` right now, this will never match the following call: ```d foo(1,2) ``` But with tuples, we could just instantiate it with `T=(int,int)` and then the call should match. This is the main reason why the tuple DIP did not attempt to allow calling a function with a single tuple parameter with multiple arguments, but of course ideally it should work...
Jan 09 2022
next sibling parent zjh <fqbqrr 163.com> writes:
On Sunday, 9 January 2022 at 10:35:03 UTC, Timon Gehr wrote:

`C++` has `...` To extend the calling parameters, very 
comfortable.
If only `d` had it.
Jan 09 2022
prev sibling parent reply zjh <fqbqrr 163.com> writes:
On Sunday, 9 January 2022 at 10:35:03 UTC, Timon Gehr wrote:

`C++` has `...` To extend the calling parameters, very 
comfortable.
If only `d` had it.
Jan 09 2022
parent reply max haughton <maxhaton gmail.com> writes:
On Sunday, 9 January 2022 at 12:38:59 UTC, zjh wrote:
 On Sunday, 9 January 2022 at 10:35:03 UTC, Timon Gehr wrote:

 `C++` has `...` To extend the calling parameters, very 
 comfortable.
 If only `d` had it.
D does have it
Jan 09 2022
parent zjh <fqbqrr 163.com> writes:
On Sunday, 9 January 2022 at 12:48:37 UTC, max haughton wrote:

 D does have it
folding expression `...`,like this: ```d template<class...A,class...B> required allsame<A...>&&allsame<B...> void f(map<A,B>&...t){ (print(t.size()),...);//here. } ```
Jan 09 2022
prev sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 1/3/2022 7:09 PM, Timon Gehr wrote:
 My DIP draft extends "alias this" to allow this (which should work anyway):
 
 alias Seq(T...)=T;
 struct S{
      byte b;
      int c;
      alias this=Seq!(b,c);
 }
 
 void func(byte,int);
 
 func(S());
I confess, this makes me uneasy. `alias this` produced a lot of unintended consequences. I'm gunshy of extending it. I'd prefer: func(S().tupleof);
 It 
 does have some significant drawbacks, e.g. `foo(int,int)` and `foo((int,int))` 
 would have a different ABI and the second overload can't be called as 
 `foo(1,2);`...
I tried to actively avoid that :-)
 To be very clear, I want this:
 
 [(1,2),(3,4)].map!((a,b)=>a+b).each!writeln;
 
 An this is generally what people mean when they talk about "tuples".
I understand. It looks like a worthy goal.
Jan 04 2022
next sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 05.01.22 07:33, Walter Bright wrote:
 On 1/3/2022 7:09 PM, Timon Gehr wrote:
 My DIP draft extends "alias this" to allow this (which should work 
 anyway):

 alias Seq(T...)=T;
 struct S{
      byte b;
      int c;
      alias this=Seq!(b,c);
 }

 void func(byte,int);

 func(S());
I confess, this makes me uneasy. `alias this` produced a lot of unintended consequences. I'm gunshy of extending it. I'd prefer:     func(S().tupleof); ...
Well, then let's not extend `alias this`.
 
 It does have some significant drawbacks, e.g. `foo(int,int)` and 
 `foo((int,int))` would have a different ABI and the second overload 
 can't be called as `foo(1,2);`...
I tried to actively avoid that :-)
 To be very clear, I want this:

 [(1,2),(3,4)].map!((a,b)=>a+b).each!writeln;

 An this is generally what people mean when they talk about "tuples".
I understand. It looks like a worthy goal.
How about something like opArgs, dealing specifically with this case? (i.e., a function call `foo(x)` with a single argument is immediately rewritten to `foo(x.opArgs)` if `x` has a member `opArgs`, and this rewrite is applied exactly once.)
Jan 04 2022
next sibling parent Timon Gehr <timon.gehr gmx.ch> writes:
On 05.01.22 08:28, Timon Gehr wrote:
 To be very clear, I want this:

 [(1,2),(3,4)].map!((a,b)=>a+b).each!writeln;

 An this is generally what people mean when they talk about "tuples".
I understand. It looks like a worthy goal.
How about something like opArgs, dealing specifically with this case? (i.e., a function call `foo(x)` with a single argument is immediately rewritten to `foo(x.opArgs)` if `x` has a member `opArgs`, and this rewrite is applied exactly once.)
(This would apply symmetrically at the call site, so that if we define a function `foo(T x)`, where T has an opArgs, it's `foo(typeof(T.opArgs) x)` instead.)
Jan 04 2022
prev sibling next sibling parent reply Paul Backus <snarwin gmail.com> writes:
On Wednesday, 5 January 2022 at 07:28:41 UTC, Timon Gehr wrote:
 How about something like opArgs, dealing specifically with this 
 case? (i.e., a function call `foo(x)` with a single argument is 
 immediately rewritten to `foo(x.opArgs)` if `x` has a member 
 `opArgs`, and this rewrite is applied exactly once.)
This mechanism seems too powerful to me; for example, one could write code like the following: struct S { string opArgs; } string fun(S s) { return "S overload"; } string fun(string s) { return "string overload"; } void main() { assert(fun(S()) == "S overload"); // fails } If there is to be any mechanism for automatic expansion of tuples, it should probably be narrow enough to avoid enabling surprises like this one.
Jan 05 2022
next sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 1/5/22 23:42, Paul Backus wrote:
 On Wednesday, 5 January 2022 at 07:28:41 UTC, Timon Gehr wrote:
 How about something like opArgs, dealing specifically with this case? 
 (i.e., a function call `foo(x)` with a single argument is immediately 
 rewritten to `foo(x.opArgs)` if `x` has a member `opArgs`, and this 
 rewrite is applied exactly once.)
This mechanism seems too powerful to me; for example, one could write code like the following:     struct S {         string opArgs;     }     string fun(S s) { return "S overload"; }     string fun(string s) { return "string overload"; }     void main() {         assert(fun(S()) == "S overload"); // fails     } If there is to be any mechanism for automatic expansion of tuples, it should probably be narrow enough to avoid enabling surprises like this one.
Why is that a surprise? You could similarly do something like: alias S=AliasSeq!(string);
Jan 05 2022
parent reply Paul Backus <snarwin gmail.com> writes:
On Wednesday, 5 January 2022 at 23:56:03 UTC, Timon Gehr wrote:
 On 1/5/22 23:42, Paul Backus wrote:
 On Wednesday, 5 January 2022 at 07:28:41 UTC, Timon Gehr wrote:
 How about something like opArgs, dealing specifically with 
 this case? (i.e., a function call `foo(x)` with a single 
 argument is immediately rewritten to `foo(x.opArgs)` if `x` 
 has a member `opArgs`, and this rewrite is applied exactly 
 once.)
This mechanism seems too powerful to me; for example, one could write code like the following: [...]
Why is that a surprise? You could similarly do something like: alias S=AliasSeq!(string);
Perhaps this is a better illustration: struct A { B opArgs() { return B(); } } struct B {} string fun(A) { return "A"; } string fun(B) { return "B"; } void main() { assert(fun(A()) == "A"); // fails } It's perfectly logical if you know about opArgs and have the definition of A in front of you, but it's extremely surprising and unintuitive if you don't.
Jan 05 2022
next sibling parent Timon Gehr <timon.gehr gmx.ch> writes:
On 1/6/22 06:58, Paul Backus wrote:
 Why is that a surprise? You could similarly do something like:

 alias S=AliasSeq!(string);
Perhaps this is a better illustration: ...
No, it's the same thing. I understand what you are saying, I just don't agree it's important or likely to cause surprises in practice.
      struct A {
          B opArgs() { return B(); }
      }
 
      struct B {}
 
      string fun(A) { return "A"; }
      string fun(B) { return "B"; }
 
      void main() {
          assert(fun(A()) == "A"); // fails
      }
 
 It's perfectly logical if you know about opArgs and have the definition 
 of A in front of you, but it's extremely surprising and unintuitive if 
 you don't.
Again, why is that different from the alias case? Furthermore, why would you use this feature willy-nilly in the first place without an intention to implement tuple semantics? "You can use this feature to write bad code" is a weak argument, it applies to every language feature.
Jan 06 2022
prev sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 1/6/22 06:58, Paul Backus wrote:

 
 Perhaps this is a better illustration:
 
      struct A {
          B opArgs() { return B(); }
      }
 
      struct B {}
 
      string fun(A) { return "A"; }
      string fun(B) { return "B"; }
 
      void main() {
          assert(fun(A()) == "A"); // fails
      }
BTW, it should work like this: ```d void foo(string x){} // <- a string, not a tuple void foo(string x,){} // <- unary tuple void foo((string,) t){} // <- unary tuple void foo(string x,int y){} // <- 2-tuple void foo((string,int) t){} // <- 2-tuple ``` So perhaps your example would not even work that way; unary tuples shouldn't decay into the underlying type. The concept will need some fleshing out. Maybe it's indeed too hard to actually retrofit this into the language...
Jan 06 2022
next sibling parent Paul Backus <snarwin gmail.com> writes:
On Thursday, 6 January 2022 at 13:18:56 UTC, Timon Gehr wrote:
 BTW, it should work like this:

 ```d
 void foo(string x){}       // <- a string, not a tuple

 void foo(string x,){}      // <- unary tuple
 void foo((string,) t){}    // <- unary tuple

 void foo(string x,int y){} // <- 2-tuple
 void foo((string,int) t){} // <- 2-tuple
 ```

 So perhaps your example would not even work that way; unary 
 tuples shouldn't decay into the underlying type. The concept 
 will need some fleshing out. Maybe it's indeed too hard to 
 actually retrofit this into the language...
Actually I think you were on the right track in [your earlier post][1], with this example: ```d void foo(int a, string b){} // pattern (int a,string b) foo(1,"2"); // match tuple (1,"2") ``` i.e., the argument list itself should be treated like a tuple, and one could also write ```d auto tup = (1, "2"); foo(tup); ``` In fact, this is how tuples already work in D, just with nicer syntax--`(1, "2")` instead of `tuple(1, "2").expand`. What the current language *can't* do, without using wrapper structs like `std.typecons.Tuple`, is nest tuples. In other words, the question we need to answer is perhaps better framed as "when *aren't* tuples expanded?" [1]: https://forum.dlang.org/post/sr5b4a$ogr$1 digitalmars.com
Jan 06 2022
prev sibling parent reply Max Samukha <maxsamukha gmail.com> writes:
On Thursday, 6 January 2022 at 13:18:56 UTC, Timon Gehr wrote:

 void foo(string x,){}      // <- unary tuple
While you are correct, it is likely to be a breaking change. Currently (string x,) is allowed and means the same as (string x).
Jan 08 2022
parent Timon Gehr <timon.gehr gmx.ch> writes:
On 1/8/22 11:28, Max Samukha wrote:
 On Thursday, 6 January 2022 at 13:18:56 UTC, Timon Gehr wrote:
 
 void foo(string x,){}      // <- unary tuple
While you are correct, it is likely to be a breaking change. Currently (string x,) is allowed and means the same as (string x).
True.
Jan 09 2022
prev sibling next sibling parent reply Tejas <notrealemail gmail.com> writes:
On Wednesday, 5 January 2022 at 22:42:14 UTC, Paul Backus wrote:
 On Wednesday, 5 January 2022 at 07:28:41 UTC, Timon Gehr wrote:
 How about something like opArgs, dealing specifically with 
 this case? (i.e., a function call `foo(x)` with a single 
 argument is immediately rewritten to `foo(x.opArgs)` if `x` 
 has a member `opArgs`, and this rewrite is applied exactly 
 once.)
This mechanism seems too powerful to me; for example, one could write code like the following: struct S { string opArgs; } string fun(S s) { return "S overload"; } string fun(string s) { return "string overload"; } void main() { assert(fun(S()) == "S overload"); // fails } If there is to be any mechanism for automatic expansion of tuples, it should probably be narrow enough to avoid enabling surprises like this one.
Yeah, and what does "exactly once" mean here? ```d struct S { string opArgs; } string fun(S s) { return "S overload"; } string fun(string s) { return "string overload"; } void main() { S s = S(); assert(fun(s) == "string overload"); // succeeds assert(fun(s) == "S overload"); // this also succeeds?? } ```
Jan 05 2022
parent Paul Backus <snarwin gmail.com> writes:
On Thursday, 6 January 2022 at 02:56:52 UTC, Tejas wrote:
 On Wednesday, 5 January 2022 at 22:42:14 UTC, Paul Backus wrote:
 On Wednesday, 5 January 2022 at 07:28:41 UTC, Timon Gehr wrote:
 How about something like opArgs, dealing specifically with 
 this case? (i.e., a function call `foo(x)` with a single 
 argument is immediately rewritten to `foo(x.opArgs)` if `x` 
 has a member `opArgs`, and this rewrite is applied exactly 
 once.)
[...]
Yeah, and what does "exactly once" mean here?
I assume it means "once per argument"; i.e., the rewrite is not applied recursively to its own result. For example: ```d struct A { B opArgs; } struct B { C opArgs; } struct C {} string fun(A) { return "A"; } string fun(B) { return "B"; } string fun(C) { return "C"; } void main() { assert(fun(A()) == "B"); } ``` `A()` is rewritten to `A().opArgs`, but `A().opArgs` is **not** rewritten to `A().opArgs.opArgs`.
Jan 05 2022
prev sibling parent reply bauss <jj_1337 live.dk> writes:
On Wednesday, 5 January 2022 at 22:42:14 UTC, Paul Backus wrote:
 On Wednesday, 5 January 2022 at 07:28:41 UTC, Timon Gehr wrote:
 How about something like opArgs, dealing specifically with 
 this case? (i.e., a function call `foo(x)` with a single 
 argument is immediately rewritten to `foo(x.opArgs)` if `x` 
 has a member `opArgs`, and this rewrite is applied exactly 
 once.)
This mechanism seems too powerful to me; for example, one could write code like the following: struct S { string opArgs; } string fun(S s) { return "S overload"; } string fun(string s) { return "string overload"; } void main() { assert(fun(S()) == "S overload"); // fails } If there is to be any mechanism for automatic expansion of tuples, it should probably be narrow enough to avoid enabling surprises like this one.
You could just make sure that the root type is always used if an overload is available for it. Just like if you did: ```d struct S { string opArgs; alias opArgs this; } ```
Jan 05 2022
next sibling parent Timon Gehr <timon.gehr gmx.ch> writes:
On 1/6/22 08:14, bauss wrote:
 On Wednesday, 5 January 2022 at 22:42:14 UTC, Paul Backus wrote:
 On Wednesday, 5 January 2022 at 07:28:41 UTC, Timon Gehr wrote:
 How about something like opArgs, dealing specifically with this case? 
 (i.e., a function call `foo(x)` with a single argument is immediately 
 rewritten to `foo(x.opArgs)` if `x` has a member `opArgs`, and this 
 rewrite is applied exactly once.)
This mechanism seems too powerful to me; for example, one could write code like the following:     struct S {         string opArgs;     }     string fun(S s) { return "S overload"; }     string fun(string s) { return "string overload"; }     void main() {         assert(fun(S()) == "S overload"); // fails     } If there is to be any mechanism for automatic expansion of tuples, it should probably be narrow enough to avoid enabling surprises like this one.
You could just make sure that the root type is always used if an overload is available for it. Just like if you did: ```d struct S {   string opArgs;   alias opArgs this; } ```
No, if you want the root type, add a trailing comma to the declaration: string fun(S s,){ return "S overload"; } string fun(string s){ return "string overload"; } (This matches unary tuple syntax (1,).)
Jan 06 2022
prev sibling next sibling parent Timon Gehr <timon.gehr gmx.ch> writes:
On 1/6/22 08:14, bauss wrote:
 
 You could just make sure that the root type is always used if an 
 overload is available for it.
 
 Just like if you did:
 
 ```d
 struct S {
    string opArgs;
    alias opArgs this;
 }
 ```
(But in general, yes, using `alias this` was my initial proposal and I once thought it's more or less viable, but Walter shot that down already.)
Jan 06 2022
prev sibling parent Paul Backus <snarwin gmail.com> writes:
On Thursday, 6 January 2022 at 07:14:49 UTC, bauss wrote:
 On Wednesday, 5 January 2022 at 22:42:14 UTC, Paul Backus wrote:
 This mechanism seems too powerful to me; for example, one 
 could write code like the following:

     struct S {
         string opArgs;
     }

     string fun(S s) { return "S overload"; }
     string fun(string s) { return "string overload"; }

     void main() {
         assert(fun(S()) == "S overload"); // fails
     }

 If there is to be any mechanism for automatic expansion of 
 tuples, it should probably be narrow enough to avoid enabling 
 surprises like this one.
You could just make sure that the root type is always used if an overload is available for it. Just like if you did: ```d struct S { string opArgs; alias opArgs this; } ```
Sure. You could make overload resolution consider a call that uses opArgs to be a "match with implicit conversion" [1], which would give it lower priority than an "exact match". Which, IMO, perfectly illustrates the problem with opArgs: it's essentially a half-assed version of user-defined implicit conversions. Not powerful enough to do everything you'd want such a feature to do, but still powerful enough to shoot yourself in the foot. [1] https://dlang.org/spec/function.html#function-overloading
Jan 06 2022
prev sibling parent Walter Bright <newshound2 digitalmars.com> writes:
On 1/4/2022 11:28 PM, Timon Gehr wrote:
 How about something like opArgs, dealing specifically with this case? (i.e., a 
 function call `foo(x)` with a single argument is immediately rewritten to 
 `foo(x.opArgs)` if `x` has a member `opArgs`, and this rewrite is applied 
 exactly once.)
Sounds like a promising idea.
Jan 08 2022
prev sibling parent reply Paul Backus <snarwin gmail.com> writes:
On Wednesday, 5 January 2022 at 06:33:39 UTC, Walter Bright wrote:
 On 1/3/2022 7:09 PM, Timon Gehr wrote:
 To be very clear, I want this:
 
 [(1,2),(3,4)].map!((a,b)=>a+b).each!writeln;
 
 An this is generally what people mean when they talk about 
 "tuples".
I understand. It looks like a worthy goal.
Is this really necessary or even desirable? Tuples do not auto-expand like this in other languages. For example, in Python: def fun(*args): print(len(args)) tup = (1, 2, 3) Even without automatic tuple expansion, Timon's example could be written as follows: alias apply(alias fun) = (args) => fun(args.tupleof); [(1,2), (3,4)].map!(apply!((a, b) => a+b)).each!writeln;
Jan 05 2022
parent Timon Gehr <timon.gehr gmx.ch> writes:
On 1/5/22 23:37, Paul Backus wrote:
 On Wednesday, 5 January 2022 at 06:33:39 UTC, Walter Bright wrote:
 On 1/3/2022 7:09 PM, Timon Gehr wrote:
 To be very clear, I want this:

 [(1,2),(3,4)].map!((a,b)=>a+b).each!writeln;

 An this is generally what people mean when they talk about "tuples".
I understand. It looks like a worthy goal.
Is this really necessary or even desirable? Tuples do not auto-expand
This is not about auto-expanding. Conceptually, functions with multiple arguments are functions that take a tuple argument. I am sure you are aware of this.
 like this in other languages.
Well, in _some_ languages. Those languages get it wrong.
 For example, in Python:
 
      def fun(*args):
          print(len(args))
 
      tup = (1, 2, 3)


 ...
Yes, and I dislike this about Python. Making multiple arguments a distinct concept from tuples on the surface is just not particularly good design. Why is _that_ desirable? It's a good example of non-orthogonal language design. ```d void foo(int a, string b){} // pattern (int a,string b) foo(1,"2"); // match tuple (1,"2") (int a, string b) = (1,"2"); // same thing void foo((int a, string b), double c){} foo((1,"2"), 3.0); ((int a,string b), double c) = ((1,"2"),3.0); ``` Why would pattern matching tuples work differently in a parameter list and elsewhere?
 Even without automatic tuple expansion, Timon's example could be written 
 as follows:
 
      alias apply(alias fun) = (args) => fun(args.tupleof);
      [(1,2), (3,4)].map!(apply!((a, b) => a+b)).each!writeln;
Clearly, but who wants to do that?
Jan 05 2022
prev sibling parent ryuukk_ <ryuukk.dev gmail.com> writes:
On Wednesday, 29 December 2021 at 05:14:43 UTC, Walter Bright 
wrote:
 Actually, I agree with the need for tuples, and am very open to 
 a good design for it.
Yes please! some love for tuples is very much needed, recently feep shared his neat lang on the IRC, and look at this beauty: https://github.com/Neat-Lang/neat/blob/master/test/runnable/tuples.nt#L6 No need of an import, no need of special types, it's built-in, using it would be sweet It's similar in GO https://gobyexample.com/multiple-return-values I love that, i wish it could be possible in D
Dec 29 2021
prev sibling next sibling parent Nick Treleaven <nick geany.org> writes:
On Sunday, 14 November 2021 at 23:05:03 UTC, Timon Gehr wrote:
...
 nullable,
Maybe: int*? x=null; writeln(*x); // error if(x) writeln(*x); // ok
Yes please.
 - type classes / some standard way to add UFCS methods to a 
 type from another module that are then visible in an 
 instantiated template from a third module
import a: S; import b: rangeFun; auto ref front(ref S s){ ... } bool empty(ref S s){ ... } void popFront(){ ... } void main(){ S s; rangeFun(s with(front, empty, popFront)); alias T=S with (front,empty,popFront); T t=s; rangeFun(t); }
Does the `s with...` expression have to keep the same source type? If not we could make a type constructor template `methodize!(S,.)` which wraps the source type but has methods which wrap all public functions in the given module that have a first parameter of the source type.
 - `let Statement in Expression` expression
void main(){ auto z = { int x=1; int y=2; } in x+y; assert(z==3); }
 - `Expression where Statement` expression
...
void main(){ auto z = x+y where{ int x=1; int y=2; }; assert(z==3); }
Isn't this sufficient?: auto z = { int x=1; int y=2; return x+y; }();
 See above. Unfortunately I only had time to give some contrived 
 examples.

 - mixin identifiers
example?
static foreach((name, value);[("x",1),("y",2),("z",3)]){ int mixin(name) = value; } writeln(x," ",y," ",z); // 1 2 3
Yes please.
 - template literals
example?
enum sizes = staticMap!((B)!=>B.sizeof,Types);
I like 'alias template literal' syntax: `alias(B) => B.sizeof` The only problem is currently `alias e = 5;` doesn't compile (at least on run.dlang.org). That is inconsistent as non-literal value expressions work.
 - consistent treatment of operators for built-in types, e.g. 
 1.opBinary!"+"(2) should work.
Seems we could add a few UFCS functions to object.d for that.
 - range literals
what's that?
auto b = (fun(x) for x in iota(100) if bar(x)); // equivalent to: // auto b = iota(100).filter!(x=>bar(x)).map!(x=>fun(x));
Maybe a template would make the current code a bit nicer: auto b = iota(100).mapFilter!(x => bar(x) ? fun(x) : none);
 - strong variable updates (probably not happening)
what's that?
int x=2; x="123"; static assert(is(typeof(x)==string));
Seems bug prone unless it used special syntax to take a value of another type.
 auto f=File(x,"r");
 static assert(is(typeof(f)==File));
 f.close();
 static assert(is(typeof(f)==ClosedFile));
If we had affine typing, it would be simpler to just design `f.close` to invalidate any use of `f`, like your example calling `move` or `destroy`. (I suppose e.g. `f.closeForNow` would not invalidate `f` if needed).
Nov 15 2021
prev sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 11/14/2021 3:05 PM, Timon Gehr wrote:
 Another issue is that it slightly expands 
 `alias this` and I am not sure whether that's a direction Walter is willing to 
 invest in at this point.
`alias this` suffers from being under-specified. In an attempt to fix that, I discovered it runs smack into multiple inheritance land, something I've tried to avoid. Worse, its implementation does a half-baked job of multiple inheritance, and backwards compatibility interferes with fixing it. To move forward with it, it would have to be abandoned in its current form and completely redesigned.
Dec 28 2021
parent 12345swordy <alexanderheistermann gmail.com> writes:
On Wednesday, 29 December 2021 at 05:13:55 UTC, Walter Bright 
wrote:

 To move forward with it, it would have to be abandoned in its 
 current form and completely redesigned.
I am in strong favor of being replaced rather than redesigned. The only thing that is preventing alias this from being replaced entirely is implicit conversions, which incidentally is a common use of alias this. D can do implicit conversions differently than C++, as there are other languages out there that have implicit conversions that is (IMO at least) sane and reasonable. The question is Walter: Are you willing to bite the bullet on this or you rather look for some alternative solution here? -Alex
Dec 28 2021
prev sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 12.10.21 23:38, Timon Gehr wrote:
 * Features you'd like to see in D
Another thing I have sometimes wished for, but forgot to include: - package and module templates
Nov 22 2021
next sibling parent reply bauss <jj_1337 live.dk> writes:
On Tuesday, 23 November 2021 at 07:55:45 UTC, Timon Gehr wrote:
 On 12.10.21 23:38, Timon Gehr wrote:
 * Features you'd like to see in D
Another thing I have sometimes wished for, but forgot to include: - package and module templates
What do you mean by that? Something like this? Or? ```d module main; import a!5; void main() { auto foo = new Foo; foo.field4 = 10; } ``` ```d module a(int fieldCount); import std.string : format; class Foo { static foreach (i; 0 .. fieldCount) { mixin(format("int field%d", i)); } } ```
Nov 23 2021
next sibling parent Timon Gehr <timon.gehr gmx.ch> writes:
On 11/23/21 10:09 AM, bauss wrote:
 On Tuesday, 23 November 2021 at 07:55:45 UTC, Timon Gehr wrote:
 On 12.10.21 23:38, Timon Gehr wrote:
 * Features you'd like to see in D
Another thing I have sometimes wished for, but forgot to include: - package and module templates
What do you mean by that? Something like this? Or? ```d module main; import a!5; void main() {     auto foo = new Foo;     foo.field4 = 10; } ``` ```d module a(int fieldCount); import std.string : format; class Foo {     static foreach (i; 0 .. fieldCount)     {         mixin(format("int field%d", i));     } } ```
Yes, something like this. Thanks for clarifying! This is a module template, I am not sure what's the best way to parameterize an entire package, maybe the declaration should be in every file like this: module package_(T).a;
Nov 23 2021
prev sibling parent reply Stefan Koch <uplink.coder googlemail.com> writes:
On Tuesday, 23 November 2021 at 09:09:03 UTC, bauss wrote:
 On Tuesday, 23 November 2021 at 07:55:45 UTC, Timon Gehr wrote:
 On 12.10.21 23:38, Timon Gehr wrote:
 * Features you'd like to see in D
Another thing I have sometimes wished for, but forgot to include: - package and module templates
What do you mean by that? Something like this? Or? ```d module main; import a!5; void main() { auto foo = new Foo; foo.field4 = 10; } ``` ```d module a(int fieldCount); import std.string : format; class Foo { static foreach (i; 0 .. fieldCount) { mixin(format("int field%d", i)); } } ```
I think that is what he means. template modules are something I have thought about, it's a simple addition but I fear they might not be advisable in the long run. Unfortunately I cannot really put my finger onto why that might be. I have a vague sense that this feature would lead to un-synchronized changes which are meant to be synchronized.
Nov 23 2021
parent Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= <ola.fosheim.grostad gmail.com> writes:
On Tuesday, 23 November 2021 at 14:09:56 UTC, Stefan Koch wrote:
 template modules are something I have thought about, it's a 
 simple addition but I fear they might not be advisable in the 
 long run.
IIRC, Bjarne Stroustrup was advised to use the less problematic scheme of having parametric modules for C++, but he went with the more problematic templates instead. :-)
Nov 23 2021
prev sibling parent reply Tejas <notrealemail gmail.com> writes:
On Tuesday, 23 November 2021 at 07:55:45 UTC, Timon Gehr wrote:
 On 12.10.21 23:38, Timon Gehr wrote:
 * Features you'd like to see in D
Another thing I have sometimes wished for, but forgot to include: - package and module templates
You mean showing the `static this()` to accept parameters? That'd be amazing 😄
Nov 23 2021
parent Tejas <notrealemail gmail.com> writes:
On Tuesday, 23 November 2021 at 10:15:52 UTC, Tejas wrote:
 On Tuesday, 23 November 2021 at 07:55:45 UTC, Timon Gehr wrote:
 On 12.10.21 23:38, Timon Gehr wrote:
 * Features you'd like to see in D
Another thing I have sometimes wished for, but forgot to include: - package and module templates
You mean showing the `static this()` to accept parameters? That'd be amazing 😄
Not showing, I meant 'allowing'
Nov 23 2021
prev sibling next sibling parent sarn <sarn theartofmachinery.com> writes:
On Monday, 11 October 2021 at 15:59:10 UTC, Atila Neves wrote:
 I'm brainstorming about what I'll talk about at DConf, and 
 during a conversation with Walter I thought it might be cool to 
 talk about:

 * Worst features implemented in a non-toy language
Go's implicit duck-typing of structs to interfaces. Things don't accidentally match a non-trivial interface, and hardly anyone wants to make an interface for a struct that some third party manages (just wrapping the struct would more idiomatic for Go). For the sake of saving a one-line inheritance specifier, this magic makes it so much harder to figure out which structs are intended to match an interface in a large codebase written by multiple people. Supporting error detection without helping with error handling. Python is good because exceptions inherit from standard types that can be handled consistently (e.g., KeyError). Most other languages (including D) aren't much help here. Go misses the point by acting like "if err != nil { return err }" is actually handling errors. I agree with others that C's type declaration syntax is a non-feature. It's pointlessly "clever" and not even consistent. I've blogged about this problem here: https://theartofmachinery.com/2020/08/18/d_declarations_for_c_programmers.html I'm sure you can think of more C++ problems than me, but let me pick three that epitomise why I don't like C++ any more: SFINAE. It's powerful, but makes template metaprogramming slow at compile time, terrible to debug and hard to read. D shows that explicit constraints are better all around. Member function pointers. They're hard to use correctly and "feel" low level, but are actually very high level. D's delegates are easier to use and reason about, yet are lower level (NB: closures are higher level, but that's a different story). Sensible operator overloading for a simple number-like type takes a lot of boring boilerplate, which encourages developers to do "interesting" things with operator overloading instead. D makes the sensible things easy, so there's less of a culture of "interesting" metaprogramming hacks.
 * Worst features (in your opinion) in D
* The multiple (confusing) ways to write anonymous lambdas. * opDispatch's (lack of) error handling semantics. * Autodecoding. * Overuse of attributes. (It fills the type system with things that could be better done with separate notation for static checking tooling.) * Overloaded semantics of . that makes namespacing hard in practice. * The hacky non-virtual destructor implementation.
 * Features you'd like to see in D
Overall, I don't think D needs many more features. But because you asked: * Better value analysis to make integer promotion issues less annoying. * Better error handling for opDispatch. * Native tuple support (with destructuring, etc.).
 Ideas? Examples?

 Thanks!
Oct 12 2021
prev sibling next sibling parent reply Jacob Carlborg <doob me.com> writes:
On Monday, 11 October 2021 at 15:59:10 UTC, Atila Neves wrote:

 * Worst features implemented in a non-toy language
I can't believe no one has mentioned this yet: PHP register globals. That is, the feature that creates variables in your scripts from request parameters.
 * Worst features (in your opinion) in D
Difficult to say, but all the half implemented features.
 * Features you'd like to see in D
* Non nullable pointers and reference types by default * Built-in or syntax sugar for optional types * Native tuples with destruction and named values: ```d (int, string) tup = (1, "foo"); auto (a, b) = tup; (int, int) point = (x: 2, y: 4); auto x = point.x + a; ``` * Some form of zero overhead exceptions. Example: ```d struct PermissionDenied {} struct FileNotFound {} int open(string filename) throw(PermissionDenied, FileNotFound); string readFile(string filename) throw(auto) { auto fd = open(filename); // ... } void main() { try auto content = readFile("foo.txt"); catch (PermissionDenied e) {} catch (FileNotFound e) {} } ``` The above is lowered to: ```d struct PermissionDenied {} struct FileNotFound {} Result!(int, PermissionDenied, FileNotFound) open(string filename); Result!(string, PermissionDenied, FileNotFound) readFile(string filename) { R0 __tmp0 = open(filename); int fd = void; switch (__tmp0.tag) { case R0.Tag.success: fd = __tmp0.value; // ... break; case R0.Tag.error0: return typeof(return)(__tmp0.error0); case R0.Tag.error1: return typeof(return)(__tmp0.error1); } } void main() { R0 __tmp0 = readFile("foo.txt"); string content = void; switch (__tmp0.tag) { case R0.Tag.success: content = __tmp0.value; break; case R0.Tag.error0: PermissionDenied e = __tmp0.error0; break; case R0.Tag.error1: FileNotFound e = __tmp0.error1; break; } } ``` -- /Jacob Carlborg
Oct 13 2021
next sibling parent reply Imperatorn <johan_forsberg_86 hotmail.com> writes:
On Wednesday, 13 October 2021 at 19:55:29 UTC, Jacob Carlborg 
wrote:
 On Monday, 11 October 2021 at 15:59:10 UTC, Atila Neves wrote:

 [...]
I can't believe no one has mentioned this yet: PHP register globals. That is, the feature that creates variables in your scripts from request parameters. [...]
"Native tuples with destruction", are you sure you don't want deconstruction instead 😉
Oct 13 2021
parent Jacob Carlborg <doob me.com> writes:
On Wednesday, 13 October 2021 at 20:10:06 UTC, Imperatorn wrote:

 "Native tuples with destruction", are you sure you don't want 
 deconstruction instead 😉
Yes, that's what I meant. -- /Jacob Carlborg
Oct 13 2021
prev sibling parent reply bauss <jj_1337 live.dk> writes:
On Wednesday, 13 October 2021 at 19:55:29 UTC, Jacob Carlborg 
wrote:
     (int, int) point = (x: 2, y: 4);
     auto x = point.x + a;
     ```
This would be better if the identifier was tied to the type. Like below: ```d (int x, int y) point = (2, 4); auto x = point.x + a; ``` Because with your example the following fails: ```d (int, int) getPoint1() { return (x: 2, y: 4); } (int, int) getPoint2(bool shouldGetPoint1) { if (shouldGetPoint1) return getPoint1(); return (left: 2, top: 4); // Possible error since the named values will be different?? } auto point1 = getPoint1(); auto point2 = getPoint2(true); auto point3 = getPoint2(false); writeln("%d %d", point1.x, point1.y); writeln("%d %d", point2.left, point2.top); // Error writeln("%d %d", point3.left, point3.top); ``` However it wouldn't fail if it worked like below: ```d (int x, int y) getPoint1() { return (2, 4); } (int left, int top) getPoint2(bool shouldGetPoint1) { if (shouldGetPoint1) return getPoint1(); return (2, 4); // Ok } auto point1 = getPoint1(); auto point2 = getPoint2(true); auto point3 = getPoint2(false); writeln("%d %d", point1.x, point1.y); writeln("%d %d", point2.left, point2.top); // Ok writeln("%d %d", point3.left, point3.top); ```
Oct 14 2021
parent bauss <jj_1337 live.dk> writes:
On Thursday, 14 October 2021 at 10:55:14 UTC, bauss wrote:
 On Wednesday, 13 October 2021 at 19:55:29 UTC, Jacob Carlborg 
 wrote:
     (int, int) point = (x: 2, y: 4);
     auto x = point.x + a;
     ```
This would be better if the identifier was tied to the type. Like below: ```d (int x, int y) point = (2, 4); auto x = point.x + a; ``` Because with your example the following fails: ```d (int, int) getPoint1() { return (x: 2, y: 4); } (int, int) getPoint2(bool shouldGetPoint1) { if (shouldGetPoint1) return getPoint1(); return (left: 2, top: 4); // Possible error since the named values will be different?? } auto point1 = getPoint1(); auto point2 = getPoint2(true); auto point3 = getPoint2(false); writeln("%d %d", point1.x, point1.y); writeln("%d %d", point2.left, point2.top); // Error writeln("%d %d", point3.left, point3.top); ``` However it wouldn't fail if it worked like below: ```d (int x, int y) getPoint1() { return (2, 4); } (int left, int top) getPoint2(bool shouldGetPoint1) { if (shouldGetPoint1) return getPoint1(); return (2, 4); // Ok } auto point1 = getPoint1(); auto point2 = getPoint2(true); auto point3 = getPoint2(false); writeln("%d %d", point1.x, point1.y); writeln("%d %d", point2.left, point2.top); // Ok writeln("%d %d", point3.left, point3.top); ```
Ofc. these are supposed to be writefln and not writeln.
Oct 14 2021
prev sibling next sibling parent deadalnix <deadalnix gmail.com> writes:
On Monday, 11 October 2021 at 15:59:10 UTC, Atila Neves wrote:
 I'm brainstorming about what I'll talk about at DConf, and 
 during a conversation with Walter I thought it might be cool to 
 talk about:

 * Worst features implemented in a non-toy language
It's a hard one. Variables implicitly declared as global in JS certainly is up there.
 * Worst features (in your opinion) in D
Pretty much anything working around the incompleteness of type qualifiers. nogc, shared being a nightmare, the impossibility of having a proper container library, all stem from the same place.
 * Features you'd like to see in D
owned as a type qualifier. Because it would fix most of the problems for which many features have been introduced. I think we could reduce the language size overall by adding this one.
Oct 13 2021
prev sibling next sibling parent reply JN <666total wp.pl> writes:
On Monday, 11 October 2021 at 15:59:10 UTC, Atila Neves wrote:
 I'm brainstorming about what I'll talk about at DConf, and 
 during a conversation with Walter I thought it might be cool to 
 talk about:

 * Worst features implemented in a non-toy language
 * Worst features (in your opinion) in D
 * Features you'd like to see in D

 Ideas? Examples?

 Thanks!
Worst features in a non-toy language. This is going to be controversial, but templates. They start innocent enough, just a way for functions to work with generic arguments. But then you build templates upon templates, and suddenly IDEs get lost, auto-refactoring stops becoming a possibility because most code doesn't exist yet, and you have to read documentation to understand what the return types and input types are of method T doStuff(T, U)(T val, U min, U max); I wouldn't say worst, but I feel like D has many features which just don't get much use. For example contracts. Sure, they sound nice in principle, and I am sure there are some users of that feature. There's nothing wrong with that, but every feature adds more complexity and bugs to fix. Features I'd like to see in D? Named arguments and struct/associative array initializers working outside of initialization, e.g. as function arguments. Some syntactic sugar I like from other languages: Named constructors as a replacement for factory static methods: ```d class Angle { this.fromDegrees(float deg) { ... } this.fromRadians(float rad) { ... } } Angle a = new Angle.fromDegrees(90.0f); ``` Initializer fields: ```d class Person { string firstName, lastName; int age; this(this.firstName, this.lastName, this.age); } Person p = new Person("Michael", "Schumacher", 52); ```
Oct 14 2021
parent bauss <jj_1337 live.dk> writes:
On Thursday, 14 October 2021 at 11:06:00 UTC, JN wrote:
 Named constructors as a replacement for factory static methods:

 ```d
 class Angle {
     this.fromDegrees(float deg) { ... }
     this.fromRadians(float rad) { ... }
 }

 Angle a = new Angle.fromDegrees(90.0f);
 ```
You can somewhat hack your way to it, by generating static functions at compile-time. Of course they're not real constructors, so immutable cannot be used and you can't utilize it like `new Angle.fromDegrees(90.0f)` and will have to do it like `Angle.fromDegrees(90.0f)` instead. Example: ```d class Angle { private: this(){} Ctor void _fromDegrees(float deg) { writeln("from degrees"); } Ctor void _fromRadians(float rad) { writeln("from radians"); } mixin NamedConstructors!Angle; } void main() { auto a = Angle.fromDegrees(90.0f); auto b = Angle.fromRadians(90.0f); } ``` Implementation of the hacky stuff: ```d struct Ctor {} template ParametersFullyQualified(alias fun) { Tuple!(string,string)[] produceIndexed(T)(T[] a, T[] b) { Tuple!(string,string)[] produced = []; if (a.length == b.length) { foreach (i; 0 .. a.length) { produced ~= tuple(a[i], b[i]); } } return produced; } enum ParametersTypeArray = Parameters!(fun).stringof[1..$-1].split(", "); enum ParameterNamesArray = [ParameterIdentifierTuple!(fun)]; enum ParametersFullyQualified = produceIndexed(ParametersTypeArray, ParameterNamesArray).map!(t => t[0] ~ " " ~ t[1]).join(", "); } mixin template NamedConstructors(T) { public: static: static foreach (member; __traits(derivedMembers, T)) { static if (mixin("hasUDA!(" ~ T.stringof ~ "." ~ member ~ ", Ctor)")) { mixin(T.stringof ~ " " ~ member[1 .. $] ~ "(" ~ ParametersFullyQualified!(mixin(T.stringof ~ "." ~ member)) ~ ") { auto o = new " ~ T.stringof ~ "(); o." ~ member ~ "(" ~ [ParameterIdentifierTuple!(mixin(T.stringof ~ "." ~ member))].join(", ") ~ "); return o; }"); } } } ```
Oct 14 2021
prev sibling next sibling parent reply IGotD- <nise nise.com> writes:
On Monday, 11 October 2021 at 15:59:10 UTC, Atila Neves wrote:
 * Worst features implemented in a non-toy language
This is not a feature but a language design question. One of the worst thins you can ever do to language is to mix language paradigms. This totally messes up the language as well as your brain. One of example is C++ template programming which is based on ML. Lately in newer C++ they have tried to taint that mistake up by adding static if and and other things. However, this hasn't completely removed the difficulties with C++ templates and they have added so many things that you might end up even more confused. You would think that C++ was the last making that mistake but no, Rust did it again. Rust decided to include macro_rules which uses a declarative syntax. Just as in C++ this totally messes up the readability and your way of thinking. Later on Rust realized the mistake and added function macros as well. Do not make computer languages schizophrenic by mixing programming paradigms.
Oct 14 2021
parent reply Nicholas Wilson <iamthewilsonator hotmail.com> writes:
On Thursday, 14 October 2021 at 18:55:53 UTC, IGotD- wrote:
 On Monday, 11 October 2021 at 15:59:10 UTC, Atila Neves wrote:
 * Worst features implemented in a non-toy language
This is not a feature but a language design question. One of the worst thins you can ever do to language is to mix language paradigms. This totally messes up the language as well as your brain. One of example is C++ template programming which is based on ML. Lately in newer C++ they have tried to taint that mistake up by adding static if
they added `if constexpr` not `static if`, which is another thing to add to the list of worst features implemented. The critical difference is that `if constexpr` always adds a scope whereas `static if` doesn't. Adding a scope if you need it costs you {}. This prevents `if constexpr` from being able to conditionally declare declarations (variables, members, members functions etc.)
Oct 14 2021
parent Stefan Koch <uplink.coder gmail.com> writes:
On Friday, 15 October 2021 at 03:38:56 UTC, Nicholas Wilson wrote:
 they added `if constexpr` not `static if`, which is another 
 thing to add to the list of worst features implemented. The 
 critical difference is that `if constexpr` always adds a scope 
 whereas `static if` doesn't. Adding a scope if you need it 
 costs you {}. This prevents `if constexpr` from being able to 
 conditionally declare declarations (variables, members, members 
 functions etc.)
Actually that avoids many tricky problems in the compiler implementation. When an inline metaprogram can add declarations that requires the compiler to have support for deferred and partial symbol resolution. At least if you want it work consistently. Static if, works in most cases that I've seen it used... But then again a case that didn't work wouldn't end up in production code so it's hard to tell. When you start playing around with it a bit you'll find it can have very bizarre behavior.
Oct 15 2021
prev sibling next sibling parent reply Antonio <antonio abrevia.net> writes:
On Monday, 11 October 2021 at 15:59:10 UTC, Atila Neves wrote:
 I'm brainstorming about what I'll talk about at DConf, and 
 during a conversation with Walter I thought it might be cool to 
 talk about:

 * Worst features implemented in a non-toy language
 * Worst features (in your opinion) in D
 * Features you'd like to see in D

 Ideas? Examples?

 Thanks!
About Wrong D features: In my opinion, **D is afraid of embracing decisions with all it's consequences**... it maintains itself in a position where nothing is "the best for niche X" **i.e.:** UFCS has not been really embraced with all it's consequences D doesn't allow this ```d "hello".(s){ s.writeln; } ``` Of course, you can introduce a template like ```auto doWith(alias f,T)(T v)=>f(v)``` or use the "pipe!" template: ```d "hello".doWith!((s){ s.writeln; }) ``` But then yo find you can't do this ```d void x(string s){ s.writeln; } "hello".x; ``` **i.e.:** The "Nullable" allien!!! D has a complete functional library based on ranges But then, you find an alien named "Nullable" that is not the equivalent to Optional/Some/None and has not the range capabilities (map, fold, ...). How difficult will be to embrace the Optional/Some/None pattern in phobos? D needs to assume it's responsibility standardizing this kind of decisions giving a solid base to other "high level" libraries like database ones (i.e.: managing nullable fields in a "functional" way using the Optional pattern). **i.e.:** GC/Not GC. I really don't want to enter here, but I'm unhappy with this kind of discussions and I find myself driven to use other languages where they have made that decision clearly: Nim has GC (you can select the GC strategy), Rust has not GC. **i.e.:** **Official "high level" libraries for common uses** (i.e.: Database libraries) 1 week ago I "returned" to D after some months... I need to perform a simple database task (with postgres) and I found that dpq2 was the most "recommended" one (Dlang site itself). It has vibe-d dependency (nice!!! may be it's based on fibers!!!) The library didn't compile (it references an old vive-d version with deprecated code)... I created an issue on github with the problem and maintainer didn't recognize the problem (initially). Finally I modified manually the library and tried to run the example proposed in "examples" folder but DMD couldn't compile because some strange missing things on system libraries with my Ubuntu... I have not mentioned that for checking it, I first created an small webserver using **the example you can find in D home page**... surprise!!! it didn't compile neither because references the same vive-d deprecated version (after updating the version, all worked enought). It was enough for me. May be next year :-) (and it will be my N-D try).
Oct 15 2021
next sibling parent reply IGotD- <nise nise.com> writes:
On Friday, 15 October 2021 at 09:47:48 UTC, Antonio wrote:
 Rust has not GC.
Rust has GC, i.e. reference counting. This is also often required with multiple ownership which you often end up with in data structures. I would rather say GC is mandatory in Rust, unless you want to take the unsafe approach. It's a matter what you regard as GC. Is only tracing GC regarded as true GC?
Oct 15 2021
parent Antonio <antonio abrevia.net> writes:
On Friday, 15 October 2021 at 09:53:18 UTC, IGotD- wrote:
 On Friday, 15 October 2021 at 09:47:48 UTC, Antonio wrote:
 Rust has not GC.
Rust has GC, i.e. reference counting. This is also often required with multiple ownership which you often end up with in data structures. I would rather say GC is mandatory in Rust, unless you want to take the unsafe approach. It's a matter what you regard as GC. Is only tracing GC regarded as true GC?
Hi IGotD- really fast response :-) Nim has reference counting too (combined with "cycle" detection "true" GC)... I really love not to use the "ownership" pattern (it's like strait jacket)... some "functional" tries with Rust results in "hard to read" code... As time goes by, I find it harder to be imperative. When I say that GC/Not GC is a problem is because there is an eternal discussion in forums and D maintains itself "neutral" when, in fact, it is a GC language... There is Walter experimental tries to introduce "ownership" equivalent (at least last time I review), there is people requesting a non GC based Phobos library... I consider myself an "external observer". May be D must introduce the Nim filosofy about GC( select your best option: Pure GC, Counter + GC, Counter only) and developer must be responsible about avoiding problems under the selected scenary, and Phobos must be compatible with the most restrictive one (Counter only) My point is about D must be clear and advance, it's impossible to keep everyone happy.
Oct 15 2021
prev sibling parent reply Imperatorn <johan_forsberg_86 hotmail.com> writes:
On Friday, 15 October 2021 at 09:47:48 UTC, Antonio wrote:
 On Monday, 11 October 2021 at 15:59:10 UTC, Atila Neves wrote:
 [...]
About Wrong D features: In my opinion, **D is afraid of embracing decisions with all it's consequences**... it maintains itself in a position where nothing is "the best for niche X" [...]
I'm not sure what you mean by your gc/nogc comment. Could you clarify? D allows for all approaches afaik
Oct 15 2021
parent reply bauss <jj_1337 live.dk> writes:
On Friday, 15 October 2021 at 10:26:51 UTC, Imperatorn wrote:
 On Friday, 15 October 2021 at 09:47:48 UTC, Antonio wrote:
 On Monday, 11 October 2021 at 15:59:10 UTC, Atila Neves wrote:
 [...]
About Wrong D features: In my opinion, **D is afraid of embracing decisions with all it's consequences**... it maintains itself in a position where nothing is "the best for niche X" [...]
I'm not sure what you mean by your gc/nogc comment. Could you clarify? D allows for all approaches afaik
I think that's his problem. D doesn't have a specific philosophy about memory management.
Oct 15 2021
next sibling parent reply deadalnix <deadalnix gmail.com> writes:
On Friday, 15 October 2021 at 10:58:14 UTC, bauss wrote:
 I think that's his problem. D doesn't have a specific 
 philosophy about memory management.
This is fine. But here is the deal: that means D cannot have a philosophy on safety. Or have closure allocated on the GC by default. Or a gazilion other things. It's the same problem, just in another dimension: a decision is made, ut then consequences are not accepted.
Oct 15 2021
parent reply russhy <russhy gmail.com> writes:
On Friday, 15 October 2021 at 11:57:28 UTC, deadalnix wrote:
 On Friday, 15 October 2021 at 10:58:14 UTC, bauss wrote:
 I think that's his problem. D doesn't have a specific 
 philosophy about memory management.
This is fine. But here is the deal: that means D cannot have a philosophy on safety. Or have closure allocated on the GC by default. Or a gazilion other things. It's the same problem, just in another dimension: a decision is made, ut then consequences are not accepted.
using allocators aware APIs solves all of this, look at zig! it is a problem already solved, use allocators and don't assume one is using GC or other means -- on the nullable thingy, i agree 100%, we now got 2 way for ``null`` - ``null`` keyword - ``isNull`` method nice! in the std! it's standard now!..
Oct 15 2021
next sibling parent reply Paul Backus <snarwin gmail.com> writes:
On Friday, 15 October 2021 at 13:21:25 UTC, russhy wrote:
 on the nullable thingy, i agree 100%, we now got 2 way for 
 ``null``


 - ``null`` keyword

 - ``isNull`` method


 nice! in the std! it's standard now!..
This is just bad naming--`isNull` should be called `empty`. It has nothing to do with `null`.
Oct 15 2021
parent russhy <russhy gmail.com> writes:
On Friday, 15 October 2021 at 13:30:46 UTC, Paul Backus wrote:
 On Friday, 15 October 2021 at 13:21:25 UTC, russhy wrote:
 on the nullable thingy, i agree 100%, we now got 2 way for 
 ``null``


 - ``null`` keyword

 - ``isNull`` method


 nice! in the std! it's standard now!..
This is just bad naming--`isNull` should be called `empty`. It has nothing to do with `null`.
Now let's break code again and rename it!
Oct 15 2021
prev sibling next sibling parent reply deadalnix <deadalnix gmail.com> writes:
On Friday, 15 October 2021 at 13:21:25 UTC, russhy wrote:
 On Friday, 15 October 2021 at 11:57:28 UTC, deadalnix wrote:
 On Friday, 15 October 2021 at 10:58:14 UTC, bauss wrote:
 I think that's his problem. D doesn't have a specific 
 philosophy about memory management.
This is fine. But here is the deal: that means D cannot have a philosophy on safety. Or have closure allocated on the GC by default. Or a gazilion other things. It's the same problem, just in another dimension: a decision is made, ut then consequences are not accepted.
using allocators aware APIs solves all of this, look at zig! it is a problem already solved, use allocators and don't assume one is using GC or other means
Many D construct assume a GC. Which kinda is the point. Either you don't assume a GC and go the zig road, or you assume a GC. But D is trying to have its cake and eat it too, and the result is schizophrenic in nature. At some point you need to chose a path. And if you don't want to chose a path at level N to leave that to the user, then you need to pick a path at level N-1 or bellow.
Oct 15 2021
parent reply SomeGuy <someguy mailinator.com> writes:
On Friday, 15 October 2021 at 13:45:11 UTC, deadalnix wrote:
 Many D construct assume a GC. Which kinda is the point. Either 
 you don't assume a GC and go the zig road, or you assume a GC. 
 But D is trying to have its cake and eat it too, and the result 
 is schizophrenic in nature.
This problem could still be solved by making the GC just another allocator (and make it the default global allocator). D's current GC only runs when an allocation is made anyway, so doing this shouldn't break the behavior of existing code (except leaking memory if the constructs that assume GC is used, of course). Maybe from this point on those constructs can be made to use reference counting instead and make sure they're allocator-independent.
Oct 15 2021
next sibling parent reply Imperatorn <johan_forsberg_86 hotmail.com> writes:
On Friday, 15 October 2021 at 14:24:16 UTC, SomeGuy wrote:
 On Friday, 15 October 2021 at 13:45:11 UTC, deadalnix wrote:
 Many D construct assume a GC. Which kinda is the point. Either 
 you don't assume a GC and go the zig road, or you assume a GC. 
 But D is trying to have its cake and eat it too, and the 
 result is schizophrenic in nature.
This problem could still be solved by making the GC just another allocator (and make it the default global allocator). D's current GC only runs when an allocation is made anyway, so doing this shouldn't break the behavior of existing code (except leaking memory if the constructs that assume GC is used, of course). Maybe from this point on those constructs can be made to use reference counting instead and make sure they're allocator-independent.
Bring back new and make it configurable 😎
Oct 15 2021
parent Dylan Graham <dylan.graham2000 gmail.com> writes:
On Friday, 15 October 2021 at 15:17:11 UTC, Imperatorn wrote:
 On Friday, 15 October 2021 at 14:24:16 UTC, SomeGuy wrote:
 On Friday, 15 October 2021 at 13:45:11 UTC, deadalnix wrote:
[...]
This problem could still be solved by making the GC just another allocator (and make it the default global allocator). D's current GC only runs when an allocation is made anyway, so doing this shouldn't break the behavior of existing code (except leaking memory if the constructs that assume GC is used, of course). Maybe from this point on those constructs can be made to use reference counting instead and make sure they're allocator-independent.
Bring back new and make it configurable 😎
Maybe I can make LWDR do this.
Oct 15 2021
prev sibling next sibling parent reply IGotD- <nise nise.com> writes:
On Friday, 15 October 2021 at 14:24:16 UTC, SomeGuy wrote:
 This problem could still be solved by making the GC just 
 another allocator (and make it the default global allocator). 
 D's current GC only runs when an allocation is made anyway, so 
 doing this shouldn't break the behavior of existing code 
 (except leaking memory if the constructs that assume GC is 
 used, of course).

 Maybe from this point on those constructs can be made to use 
 reference counting instead and make sure they're 
 allocator-independent.
The biggest obstacle is that D has no fat pointers. It has only pointers which is enough when you have tracing GC but not enough if your pointers requires extra metadata. This is one of the biggest mistakes in D which limits the possibility to change GC type. Other languages like Nim have a reference types which is a fat pointer type. Nim has gone through more GC types in a shorter time than D. Fat pointers come at a cost though which might be extra dereferences as your data is an inner pointer member. In practice this is already possible in D as a library solution. Problem is that you cannot easily change Druntime/Phobos to also use your custom GC.
Oct 15 2021
next sibling parent reply Araq <rumpf_a web.de> writes:
On Friday, 15 October 2021 at 15:42:13 UTC, IGotD- wrote:
 On Friday, 15 October 2021 at 14:24:16 UTC, SomeGuy wrote:
 [...]
The biggest obstacle is that D has no fat pointers. It has only pointers which is enough when you have tracing GC but not enough if your pointers requires extra metadata. This is one of the biggest mistakes in D which limits the possibility to change GC type. Other languages like Nim have a reference types which is a fat pointer type. Nim has gone through more GC types in a shorter time than D. Fat pointers come at a cost though which might be extra dereferences as your data is an inner pointer member. In practice this is already possible in D as a library solution. Problem is that you cannot easily change Druntime/Phobos to also use your custom GC.
Er, that's not how Nim's "fat pointers" work and the term is either misleading or wrong, sizeof(ref) == sizeof(void*) in Nim land.
Oct 15 2021
parent reply IGotD- <nise nise.com> writes:
On Friday, 15 October 2021 at 16:05:13 UTC, Araq wrote:
 Er, that's not how Nim's "fat pointers" work and the term is 
 either misleading or wrong, sizeof(ref) == sizeof(void*) in Nim 
 land.
So how do they work then, when you have set the GC to default ORC?
Oct 15 2021
parent reply Araq <rumpf_a web.de> writes:
On Friday, 15 October 2021 at 16:10:04 UTC, IGotD- wrote:
 On Friday, 15 October 2021 at 16:05:13 UTC, Araq wrote:
 Er, that's not how Nim's "fat pointers" work and the term is 
 either misleading or wrong, sizeof(ref) == sizeof(void*) in 
 Nim land.
So how do they work then, when you have set the GC to default ORC?
The RC and metadata are stored at negative offsets.
Oct 15 2021
parent reply IGotD- <nise nise.com> writes:
On Friday, 15 October 2021 at 17:17:33 UTC, Araq wrote:
 The RC and metadata are stored at negative offsets.
I was thinking. One way for D which has common GC/raw pointers is to always allocate metadata at negative offsets. Then we D compiler can have hooks that runs when a pointer is copied, moved or goes out of scope. At negative offsets can have a flag field that tells us if the memory is GC allocated or not. If it is not GC it just jumps over the hook code. Drawbacks with this solution is the the raw C malloc/free cannot be used and a wrapped D version must be used that allocates additional space for the metadata. Also non GC memory will have a penalty with the hooks, as it needs to check the type all the time. For the current GC these hooks would be empty though. Is this penalty we can live with?
Oct 15 2021
parent Araq <rumpf_a web.de> writes:
On Saturday, 16 October 2021 at 00:16:07 UTC, IGotD- wrote:
 Is this penalty we can live with?
Probably but it's a hack, the proper solution is to fix the type system. And since this the topic already: Not distinguishing between traced and untraced pointers (or between owned and unowned pointers for that matter) is indeed one of the "worst" language features.
Oct 15 2021
prev sibling parent reply SomeGuy <someguy mailinator.com> writes:
On Friday, 15 October 2021 at 15:42:13 UTC, IGotD- wrote:
 The biggest obstacle is that D has no fat pointers. It has only 
 pointers which is enough when you have tracing GC but not 
 enough if your pointers requires extra metadata.

 This is one of the biggest mistakes in D which limits the 
 possibility to change GC type. Other languages like Nim have a 
 reference types which is a fat pointer type. Nim has gone 
 through more GC types in a shorter time than D.

 Fat pointers come at a cost though which might be extra 
 dereferences as your data is an inner pointer member. In 
 practice this is already possible in D as a library solution. 
 Problem is that you cannot easily change Druntime/Phobos to 
 also use your custom GC.
Yeah, what I was proposing is not actually for adding custom GC types, it is for gradually phasing out the GC (for libraries) and maybe replace it with some `reference counted` type like Rust has. When people complain about GC in D it's mostly because the library ecosystem is by default ` YesGC`. TBH I like having a GC and using it when I don't care about memory usage or speed. This mostly when I use D as a Python replacement and it does its job well. The problem is when I want to use D as a C++ replacement. When I try to do that, I can't D libraries that are not ` nogc`. I want library developers to design their interfaces after considering allowing the usage of different allocators. Because if that happens then I could pass the GC as the allocator parameter and not care about memory management, or maybe I want to pass my own arena allocator when I'm thinking about cache locality or whatever. Otherwise we're risking two different library ecosystems coexisting (one ` nogc` and one ` yesgc`) and that means we'll never have a good library ecosystem. Just let the application developers pass whatever allocator parameter into the libraries (and actually make the stdlib work this way to set an example). If the current situation persists, D is just "C" or "Go" with more features and much fewer libraries. I'm okay with D not having the ecosystem of C (or Rust, or Go) and building everything from ground-up, most people wouldn't be. Don't tell me we have great interop with C and C++, I'm using D because I want to minimize my exposure to C & C++. I hope the situation changes, because if it doesn't Zig will eat D's lunch even though it is actually a worse language (with probably a better ecosystem). Or maybe Jai will if the situation doesn't change before Jai is released (and everybody knows it won't be released for years, still). That'd be especially saddening since Jai is actually just D with different syntax, no GC and more powerful CTFE. That's literally it.
Oct 15 2021
parent reply deadalnix <deadalnix gmail.com> writes:
On Friday, 15 October 2021 at 16:21:32 UTC, SomeGuy wrote:
 When people complain about GC in D it's mostly because the 
 library ecosystem is by default ` YesGC`. TBH I like having a 
 GC and using it when I don't care about memory usage or speed. 
 This mostly when I use D as a Python replacement and it does 
 its job well.
You kind have to, the alternative being that the library aren't YesGC as you say, and then whatever reference they manipulate is now invisible to the GC. That may cause library users to see their object being collected when they are still alive and a whole slue of similar problem. If you want the language to support a GC, you *HAVE TO* have the library allocate anything using the GC. From there you have several options: 1/ Not use a GC at all and do manual memory management à la C++. 2/ Use a GC for everything à la Java. 3/ Not use a GC an use an ownership system instead à la Rust. 4/ Allow for manual memory management via GC free, but in which case the compiler can't prove anything, so things like safe or nogc cannot work by design. 5/ Use a GC *AND* an ownership system that allow the compiler to prove invariant about freeing (and even do a lot of it automatically) so things like safe can work (and nogc needs to forbid GC leaks rather than GC allocations). D correspond to none of the above, even though it tries to be kind of 4 kind of 5. Then end result in practice is that almost everything uses the GC, and that safe and nogc are almost useless.
Oct 15 2021
parent reply SealabJaster <sealabjaster gmail.com> writes:
On Friday, 15 October 2021 at 16:44:57 UTC, deadalnix wrote:
 Then end result in practice is that almost everything uses the 
 GC, and that  safe and  nogc are almost useless.
Is there anything we can do to start addressing this, and the other woes people have brought up? The answer is likely no, so I foresee these same things popping up over and over and over again with no resolution since we seem to have dug ourselves into a corner.
Oct 15 2021
next sibling parent reply deadalnix <deadalnix gmail.com> writes:
On Friday, 15 October 2021 at 21:55:55 UTC, SealabJaster wrote:
 On Friday, 15 October 2021 at 16:44:57 UTC, deadalnix wrote:
 Then end result in practice is that almost everything uses the 
 GC, and that  safe and  nogc are almost useless.
Is there anything we can do to start addressing this, and the other woes people have brought up? The answer is likely no, so I foresee these same things popping up over and over and over again with no resolution since we seem to have dug ourselves into a corner.
Well at some point we need to make choices about the invariant we want and stick with them. Considering D's values, I'd say the solution that make sense is to allocate using the GC, have an ownership system on top of it that can free most things safely. You'll note that is is possible to build a GC that is as fast as malloc free (for instance, I was able to build a GC on top of jemalloc, and the only thing I had to add is one hashmap store when allocating chunk of size bigger than 4MB. this happens almost never and when it does, memory allocation is usually not the problem as simply filling these 4MB with literally anything is far more work than the work the allocator does (to be 100% fair, this doesn't work with all mallocs, a tcmalloc style structure wouldn't cut it for instance, but jemalloc is notorious to be one of the fastest and bestest so we are not making a big concession). So using a GC instead of malloc/free is very much viable. In fact, because we know if something is shared or not, I bet we can do something that is even faster than traditional mallocs. So we allocate on the GC, always and use ownership on top of it. Ownership should allow you to express common allocation/disposition patterns, and when you can't, either you leak to the GC, or you free explicitly, which is unsafe. That require repurposing nogc as preventing leaking from the ownership system to the GC rather than allocating on the GC - which in itself is no problem if the allocations are freed properly. There are a ton of added benefit that come attached to this if done properly, like solving a ton of problems with shared. Even tricky situations such as nogc exception become trivial in that model. Consider: ```d void foo() { // Allocate the exception using the GC. The exception is // an owned(Exception), and the corresponding overload from // the runtime is called. // Ownership of the exception is transferred to the runtime. // The ownership system didn't lose track of the exception, so // foo can be nogc . throw new Exception(); } void bar() { try { foo(); } catch(Exception e) { // The ownership of the Exception is transferred back to the // user's code. The Exception doesn't leave the catch block, // so it can be freed automatically without the user having to // do anything. // In practice, that require the runtime to provide the // exception handler with knowledge of the exception being // owned or not and a runtime check, so that, if it is owned // it is freed. // bar can also be nogc , because either the exception is owned // in which case it is freed and no leak occurred, or the exception // is not owned, in which case the leak happened somewhere else. // In that case, this somewhere else cannot be nogc . } } ``` You'll note that the ownership system does not need to be as rich as Rust's, because there is always the option to fallback on the GC or on unsafe constructs.
Oct 15 2021
next sibling parent reply russhy <russhy gmail.com> writes:
On Friday, 15 October 2021 at 23:58:34 UTC, deadalnix wrote:
 On Friday, 15 October 2021 at 21:55:55 UTC, SealabJaster wrote:
 On Friday, 15 October 2021 at 16:44:57 UTC, deadalnix wrote:
 Then end result in practice is that almost everything uses 
 the GC, and that  safe and  nogc are almost useless.
Is there anything we can do to start addressing this, and the other woes people have brought up? The answer is likely no, so I foresee these same things popping up over and over and over again with no resolution since we seem to have dug ourselves into a corner.
Well at some point we need to make choices about the invariant we want and stick with them. Considering D's values, I'd say the solution that make sense is to allocate using the GC, have an ownership system on top of it that can free most things safely. You'll note that is is possible to build a GC that is as fast as malloc free (for instance, I was able to build a GC on top of jemalloc, and the only thing I had to add is one hashmap store when allocating chunk of size bigger than 4MB. this happens almost never and when it does, memory allocation is usually not the problem as simply filling these 4MB with literally anything is far more work than the work the allocator does (to be 100% fair, this doesn't work with all mallocs, a tcmalloc style structure wouldn't cut it for instance, but jemalloc is notorious to be one of the fastest and bestest so we are not making a big concession). So using a GC instead of malloc/free is very much viable. In fact, because we know if something is shared or not, I bet we can do something that is even faster than traditional mallocs. So we allocate on the GC, always and use ownership on top of it. Ownership should allow you to express common allocation/disposition patterns, and when you can't, either you leak to the GC, or you free explicitly, which is unsafe. That require repurposing nogc as preventing leaking from the ownership system to the GC rather than allocating on the GC - which in itself is no problem if the allocations are freed properly. There are a ton of added benefit that come attached to this if done properly, like solving a ton of problems with shared. Even tricky situations such as nogc exception become trivial in that model. Consider: ```d void foo() { // Allocate the exception using the GC. The exception is // an owned(Exception), and the corresponding overload from // the runtime is called. // Ownership of the exception is transferred to the runtime. // The ownership system didn't lose track of the exception, so // foo can be nogc . throw new Exception(); } void bar() { try { foo(); } catch(Exception e) { // The ownership of the Exception is transferred back to the // user's code. The Exception doesn't leave the catch block, // so it can be freed automatically without the user having to // do anything. // In practice, that require the runtime to provide the // exception handler with knowledge of the exception being // owned or not and a runtime check, so that, if it is owned // it is freed. // bar can also be nogc , because either the exception is owned // in which case it is freed and no leak occurred, or the exception // is not owned, in which case the leak happened somewhere else. // In that case, this somewhere else cannot be nogc . } } ``` You'll note that the ownership system does not need to be as rich as Rust's, because there is always the option to fallback on the GC or on unsafe constructs.
What is your plan to make GC incremental? what about latency sensitive applications? Can you scale the GC? servers with heaps above 1TB? Both Java and Go can scale their GC and ensure sub 1ms collection without stopping the world I hear you want to stick to the GC no matter what, did you know to target 60 FPS in games, one only has a budget of 16ms per frame Languages with GC can afford one because their GC is competitive and they put lot of R&D in constantly improving and tuning them I'm not saying GC is bad, i'm saying if you want someone to take you seriously, you have to provide serious tools so you can assist them whenever they need to scale their buisnesses Look at ASP.NET team at microsoft, they all working towards improving the C#language so it is much less reliant on the GC Span, value task, ref, stack alloc and bunch of other stuff they D's history is C/C++, why stray away from that history?
Oct 15 2021
next sibling parent deadalnix <deadalnix gmail.com> writes:
On Saturday, 16 October 2021 at 04:03:29 UTC, russhy wrote:
 What is your plan to make GC incremental? what about latency 
 sensitive applications?
I asserted to write an elaborated answered and then decided to scrap it. Your answer misses the point to a degree that qualifying it of an answer is a stretch to begin with. Long story short: none of the shit is needed if one can free explicitely, and collection cycle only are required when you leak, so really not a problem for anyone who don't leak. You'll get the same performance profile as malloc/free. End of story.
 D's history is C/C++, why stray away from that history?
Because we already have C and C++.
Oct 16 2021
prev sibling parent reply Imperatorn <johan_forsberg_86 hotmail.com> writes:
On Saturday, 16 October 2021 at 04:03:29 UTC, russhy wrote:
 On Friday, 15 October 2021 at 23:58:34 UTC, deadalnix wrote:
 [...]
What is your plan to make GC incremental? what about latency sensitive applications? [...]
Hence the solution is to improve the GC 😎
Oct 16 2021
parent reply deadalnix <deadalnix gmail.com> writes:
On Saturday, 16 October 2021 at 10:32:59 UTC, Imperatorn wrote:
 On Saturday, 16 October 2021 at 04:03:29 UTC, russhy wrote:
 On Friday, 15 October 2021 at 23:58:34 UTC, deadalnix wrote:
 [...]
What is your plan to make GC incremental? what about latency sensitive applications? [...]
Hence the solution is to improve the GC 😎
No. Well it doesn't hurt to improve the GC, but no, it isn't the solution.
Oct 16 2021
parent reply Imperatorn <johan_forsberg_86 hotmail.com> writes:
On Saturday, 16 October 2021 at 12:51:26 UTC, deadalnix wrote:
 On Saturday, 16 October 2021 at 10:32:59 UTC, Imperatorn wrote:
 On Saturday, 16 October 2021 at 04:03:29 UTC, russhy wrote:
 On Friday, 15 October 2021 at 23:58:34 UTC, deadalnix wrote:
 [...]
What is your plan to make GC incremental? what about latency sensitive applications? [...]
Hence the solution is to improve the GC 😎
No. Well it doesn't hurt to improve the GC, but no, it isn't the solution.
I inserted the emoji there but it didn't work 😑
Oct 16 2021
parent FeepingCreature <feepingcreature gmail.com> writes:
On Saturday, 16 October 2021 at 17:18:34 UTC, Imperatorn wrote:
 On Saturday, 16 October 2021 at 12:51:26 UTC, deadalnix wrote:
 On Saturday, 16 October 2021 at 10:32:59 UTC, Imperatorn wrote:
 On Saturday, 16 October 2021 at 04:03:29 UTC, russhy wrote:
 On Friday, 15 October 2021 at 23:58:34 UTC, deadalnix wrote:
 [...]
What is your plan to make GC incremental? what about latency sensitive applications? [...]
Hence the solution is to improve the GC 😎
No. Well it doesn't hurt to improve the GC, but no, it isn't the solution.
I inserted the emoji there but it didn't work 😑
Works fine here. I just think that it wasn't clear whatever you meant by it.
Oct 17 2021
prev sibling parent reply Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= <ola.fosheim.grostad gmail.com> writes:
On Friday, 15 October 2021 at 23:58:34 UTC, deadalnix wrote:
 So using a GC instead of malloc/free is very much viable. In 
 fact, because we know if something is shared or not, I bet we 
 can do something that is even faster than traditional mallocs.
Well, yes, malloc is only the default, when people want speed in system level programming they create their own allocators. In order to get to a competitive advantage, D has to decide what its primary use case is. Maybe it would be better for D to position itself as a higher level language with some lower level features. I think also GC and malloc can be combined and improved on. You could probably get better performance and less fragmentation if the allocation contained a hint of when it statistically would be released. You could also get better performance by providing information about typical allocation patterns and sizes. But without a clear vision of what the key use cases for the language is, getting a direction on all of this is going to be difficult. (Much easier to make tough decision if you have a clear picture of what the main use scenario is.)
Oct 18 2021
parent reply deadalnix <deadalnix gmail.com> writes:
On Monday, 18 October 2021 at 11:08:08 UTC, Ola Fosheim Grøstad 
wrote:
 Well, yes, malloc is only the default, when people want speed 
 in system level programming they create their own allocators.
It doesn't matter. These allocator need memory from the system and almost always use malloc do get it. Which as far as the GC is concerned, it the only thing that is needed. It doesn't matter if you malloc each object or if you malloc a large slab and then manage it manually.
Oct 18 2021
next sibling parent reply Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= <ola.fosheim.grostad gmail.com> writes:
On Monday, 18 October 2021 at 11:33:02 UTC, deadalnix wrote:
 It doesn't matter. These allocator need memory from the system 
 and almost always use malloc do get it.
Yes, but often times they don't release it until program exit.
Oct 18 2021
parent deadalnix <deadalnix gmail.com> writes:
On Monday, 18 October 2021 at 11:38:46 UTC, Ola Fosheim Grøstad 
wrote:
 On Monday, 18 October 2021 at 11:33:02 UTC, deadalnix wrote:
 It doesn't matter. These allocator need memory from the system 
 and almost always use malloc do get it.
Yes, but often times they don't release it until program exit.
That still doesn't change anything to the point made.
Oct 18 2021
prev sibling parent reply russhy <russhy gmail.com> writes:
On Monday, 18 October 2021 at 11:33:02 UTC, deadalnix wrote:
 On Monday, 18 October 2021 at 11:08:08 UTC, Ola Fosheim Grøstad 
 wrote:
 Well, yes, malloc is only the default, when people want speed 
 in system level programming they create their own allocators.
It doesn't matter. These allocator need memory from the system and almost always use malloc do get it. Which as far as the GC is concerned, it the only thing that is needed. It doesn't matter if you malloc each object or if you malloc a large slab and then manage it manually.
and then you freeze all threads and must scan all allocated pointers whenever your "gc'd malloc"'s buffer needs to grow
In order to get to a competitive advantage, D has to decide what 
its primary use case is. >Maybe it would be better for D to 
position itself as a higher level language with some >lower 
level features.
I think also GC and malloc can be combined and improved on. You 
could probably get better >performance and less fragmentation if 
the allocation contained a hint of when it >statistically would 
be released. You could also get better performance by providing 
information about typical allocation patterns and sizes.
But without a clear vision of what the key use cases for the 
language is, getting a >direction on all of this is going to be 
difficult. (Much easier to make tough decision if >you have a 
clear picture of what the main use scenario is.)
you can't compete with highlevel languages and their sub 1ms incremental GC that's very depressing to focus on whether or not we should use the GC that is not the question we should ask, the question is: what problem do we want to solve AGAIN ASP.net team is working hard on reducing the impact of the GC in their library!!!! even thought they have a competitive GC, they are making sure they don't do useless GC allocations and are using Span/stackalloc/ValueTysk everywhere!! Learn from them, don't be like their old-them and saying, we should use and embrace GC everywhere That is not how you make fast and competing software...... The smart and pragmatic approach is to give tools for people to write efficient software Allocators is one of them And it doesn't change the way people code, if they want to use a GC, they are free to do it so But go tell an graphics engine programmer to use a GC, he'll laugh at you Vulkan is meant to be used with an allocator https://gpuopen.com/vulkan-memory-allocator/ That is the pragmatic way of designing portable and efficient libraries Have we lost our mind focusing on the GC? i think yes
Oct 18 2021
next sibling parent reply deadalnix <deadalnix gmail.com> writes:
On Monday, 18 October 2021 at 14:39:35 UTC, russhy wrote:
 and then you freeze all threads and must scan all allocated 
 pointers whenever your "gc'd malloc"'s buffer needs to grow
An unsolvable problem, clearly, as it is inconceivable that the user could set a heap size. Don't believe anyone that would tell you this could boils down to a simple call to a function, such as GC.setHeapSize(XXXX), they are clearly manipulating you.
 you can't compete with highlevel languages and their sub 1ms 
 incremental GC
Let me tell you a secret. most modern languages use an hybrid approach as the one I described, and even old one have been repurposed to use that when possible (for instance python).
 AGAIN

 ASP.net team is working hard on reducing the impact of the GC 
 in their library!!!! even thought they have a competitive GC, 
 they are making sure they don't do useless GC allocations and 
 are using Span/stackalloc/ValueTysk everywhere!!
Ho, damn, a hybrid approach that allocates on the stack or the GC and frees instead of leaking. Who could have though of that?
 The smart and pragmatic approach is to give tools for people to 
 write efficient software

 Allocators is one of them
How the strawman screaming in between you hear doing?
 Have we lost our mind focusing on the GC? i think yes
With all due respect, you clearly are not able to address the points made in the discussions you are participating in. It's harsh, but it's true. You shouldn't be making statements about others losing their mind.
Oct 18 2021
parent reply russhy <russhy gmail.com> writes:
On Monday, 18 October 2021 at 15:22:30 UTC, deadalnix wrote:
 On Monday, 18 October 2021 at 14:39:35 UTC, russhy wrote:
 and then you freeze all threads and must scan all allocated 
 pointers whenever your "gc'd malloc"'s buffer needs to grow
An unsolvable problem, clearly, as it is inconceivable that the user could set a heap size. Don't believe anyone that would tell you this could boils down to a simple call to a function, such as GC.setHeapSize(XXXX), they are clearly manipulating you.
 you can't compete with highlevel languages and their sub 1ms 
 incremental GC
Let me tell you a secret. most modern languages use an hybrid approach as the one I described, and even old one have been repurposed to use that when possible (for instance python).
 AGAIN

 ASP.net team is working hard on reducing the impact of the GC 
 in their library!!!! even thought they have a competitive GC, 
 they are making sure they don't do useless GC allocations and 
 are using Span/stackalloc/ValueTysk everywhere!!
Ho, damn, a hybrid approach that allocates on the stack or the GC and frees instead of leaking. Who could have though of that?
 The smart and pragmatic approach is to give tools for people 
 to write efficient software

 Allocators is one of them
How the strawman screaming in between you hear doing?
 Have we lost our mind focusing on the GC? i think yes
With all due respect, you clearly are not able to address the points made in the discussions you are participating in. It's harsh, but it's true. You shouldn't be making statements about others losing their mind.
You miss the point.. What problem are you trying to solve? I'm trying to solve the problem that we don't encourage people to write their latency sensitive programs in D and instead fallback to C++ (game engines for example), because std isn't built in the idea that they can provide their own allocation schemes Be pragmatic, please Can we at least agree that the work on https://dlang.org/phobos/std_experimental_allocator.html must be resumed and moved out of experimental?
Oct 18 2021
parent reply bauss <jj_1337 live.dk> writes:
On Monday, 18 October 2021 at 18:12:49 UTC, russhy wrote:
 Can we at least agree that the work on 
 https://dlang.org/phobos/std_experimental_allocator.html must 
 be resumed and moved out of experimental?
std.experimental is where modules go to die. Nothing ever leaves it.
Oct 19 2021
parent Tejas <notrealemail gmail.com> writes:
On Tuesday, 19 October 2021 at 07:02:01 UTC, bauss wrote:
 On Monday, 18 October 2021 at 18:12:49 UTC, russhy wrote:
 Can we at least agree that the work on 
 https://dlang.org/phobos/std_experimental_allocator.html must 
 be resumed and moved out of experimental?
std.experimental is where modules go to die. Nothing ever leaves it.
We really should move `allocator` into normal `std` namespace though. It will somewhat help us get to parity with `Zig`, which does this at a language level, I believe.
Oct 19 2021
prev sibling parent reply Kagamin <spam here.lot> writes:
On Monday, 18 October 2021 at 14:39:35 UTC, russhy wrote:
 you can't compete with highlevel languages and their sub 1ms 
 incremental GC

 ASP.net team is working hard on reducing the impact of the GC 
 in their library!
When GC flies out of the window, it shouldn't matter whether it's sub 1ms incremental or what.
Oct 20 2021
parent reply Tejas <notrealemail gmail.com> writes:
On Wednesday, 20 October 2021 at 08:09:18 UTC, Kagamin wrote:
 On Monday, 18 October 2021 at 14:39:35 UTC, russhy wrote:
 you can't compete with highlevel languages and their sub 1ms 
 incremental GC

 ASP.net team is working hard on reducing the impact of the GC 
 in their library!
When GC flies out of the window, it shouldn't matter whether it's sub 1ms incremental or what.
Are we getting rid of the GC? :D I never read about any of that here, can you please share the source of this amazing info :)
Oct 20 2021
parent Kagamin <spam here.lot> writes:
On Wednesday, 20 October 2021 at 10:50:26 UTC, Tejas wrote:
 Are we getting rid of the GC? :D
In the ASP.net team sense.
 I never read about any of that here, can you please share the 
 source of this amazing info :)
https://dlang.org/phobos/std_container_array.html
Oct 20 2021
prev sibling parent reply russhy <russhy gmail.com> writes:
On Friday, 15 October 2021 at 21:55:55 UTC, SealabJaster wrote:
 On Friday, 15 October 2021 at 16:44:57 UTC, deadalnix wrote:
 Then end result in practice is that almost everything uses the 
 GC, and that  safe and  nogc are almost useless.
Is there anything we can do to start addressing this, and the other woes people have brought up? The answer is likely no, so I foresee these same things popping up over and over and over again with no resolution since we seem to have dug ourselves into a corner.
In the end, i think it doesn't really matter to be honest, as long as we make sure that additions to the STD doesn't make assumption about the memory allocation strategy, we'll be fine The library authors will be free to use what ever is best for their libraries/program STD will be here to assist them, rather than enforce them into something One thing to mention is that entertainment is, more and more, and faster than ever, being consumed online, in dematerialized ways, that includes games and anything VR/AR/XR There will be a massive need of software being built, games being created for various kind devices and for multiple experiences WASM will be important, game engines/framework built for it will be needed And those kind of libraries will avoid GC'd langauges to maximize perf Web stuff is a problem already solved, trying to chase it is a dead end Our best bet i believe, is believe is to target those devs, for their engine needs, they need something that helps them be in control over the memory allocations they wish, but let them consume our libraries, they'll depend on D forever, they'll appreciate D, and maybe they'll also use D for their gameplay code instead of having to glue one Making the STD empower that is i believe important I think the best short term move that will help in the very long term is to finally finish ``STD.EXPERIMENTAL.ALLOCATORS`` and put it in ``STD.MEM`` It's a little bit bloated, it'll need a little lifting What its author has to say?
Oct 15 2021
parent deadalnix <deadalnix gmail.com> writes:
On Saturday, 16 October 2021 at 05:37:40 UTC, russhy wrote:
 In the end, i think it doesn't really matter to be honest, as 
 long as we make sure that additions to the STD doesn't make 
 assumption about the memory allocation strategy, we'll be fine
That really doesn't work in practice, as it prevent libraries from allocating at all.
Oct 16 2021
prev sibling parent russhy <russhy gmail.com> writes:
On Friday, 15 October 2021 at 14:24:16 UTC, SomeGuy wrote:
 On Friday, 15 October 2021 at 13:45:11 UTC, deadalnix wrote:
 Many D construct assume a GC. Which kinda is the point. Either 
 you don't assume a GC and go the zig road, or you assume a GC. 
 But D is trying to have its cake and eat it too, and the 
 result is schizophrenic in nature.
This problem could still be solved by making the GC just another allocator (and make it the default global allocator). D's current GC only runs when an allocation is made anyway, so doing this shouldn't break the behavior of existing code (except leaking memory if the constructs that assume GC is used, of course). Maybe from this point on those constructs can be made to use reference counting instead and make sure they're allocator-independent.
Yes i agree with you, that would make everyone happy and would be transparent without breaking any existing code
Oct 15 2021
prev sibling parent Paulo Pinto <pjmlp progtools.org> writes:
On Friday, 15 October 2021 at 13:21:25 UTC, russhy wrote:
 On Friday, 15 October 2021 at 11:57:28 UTC, deadalnix wrote:
 On Friday, 15 October 2021 at 10:58:14 UTC, bauss wrote:
 [...]
This is fine. But here is the deal: that means D cannot have a philosophy on safety. Or have closure allocated on the GC by default. Or a gazilion other things. It's the same problem, just in another dimension: a decision is made, ut then consequences are not accepted.
using allocators aware APIs solves all of this, look at zig! it is a problem already solved, use allocators and don't assume one is using GC or other means -- on the nullable thingy, i agree 100%, we now got 2 way for ``null`` - ``null`` keyword - ``isNull`` method nice! in the std! it's standard now!..
Except safety, using Zig is no better than Modula-2, as it doesn't prevent use-after-free bugs.
Oct 15 2021
prev sibling parent Imperatorn <johan_forsberg_86 hotmail.com> writes:
On Friday, 15 October 2021 at 10:58:14 UTC, bauss wrote:
 On Friday, 15 October 2021 at 10:26:51 UTC, Imperatorn wrote:
 On Friday, 15 October 2021 at 09:47:48 UTC, Antonio wrote:
 On Monday, 11 October 2021 at 15:59:10 UTC, Atila Neves wrote:
 [...]
About Wrong D features: In my opinion, **D is afraid of embracing decisions with all it's consequences**... it maintains itself in a position where nothing is "the best for niche X" [...]
I'm not sure what you mean by your gc/nogc comment. Could you clarify? D allows for all approaches afaik
I think that's his problem. D doesn't have a specific philosophy about memory management.
Oh, I see 😎
Oct 15 2021
prev sibling next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
I have one!

noreturn
Oct 15 2021
parent 12345swordy <alexanderheistermann gmail.com> writes:
On Friday, 15 October 2021 at 17:14:10 UTC, Andrei Alexandrescu 
wrote:
 I have one!

 noreturn
Context: Andrei is expressing his frustration with noreturn in discord due to the poor implementation and testing of it. -Alex
Oct 15 2021
prev sibling next sibling parent Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= <ola.fosheim.grostad gmail.com> writes:
On Monday, 11 October 2021 at 15:59:10 UTC, Atila Neves wrote:
 * Worst features implemented in a non-toy language
Difficult to say, features may not be bad in isolation, but turn bad when combined with other features. Features can turn bad when they can be abused for more terse source code in ways the language designers did not intend, or when scripting languages are used for larger programs. But by-name parameter passing is pretty bad. Having expressions passed into a function executed multiple times backfires real fast in imperative languages. Such bugs can be difficult to identify.
 * Worst features (in your opinion) in D
Lack of consistency (unnecessary complexity?) in the meta-programming feature set / type system, but cannot be fixed as it would become a different language.
 * Features you'd like to see in D
Simplify the language. Flow typing. A type system that makes it possible for the compiler to reason about ownership. Implementation: clean separation between front-end and back-end.
Oct 15 2021
prev sibling next sibling parent Rumbu <rumbu rumbu.ro> writes:
On Monday, 11 October 2021 at 15:59:10 UTC, Atila Neves wrote:
 I'm brainstorming about what I'll talk about at DConf, and 
 during a conversation with Walter I thought it might be cool to 
 talk about:

 * Worst features implemented in a non-toy language
- records implementation - object promotion - array covariance - half baked generics - operator overloading verbosity - mutability by default - New nullable semantics
 * Worst features (in your opinion) in D
- Module private instead of class private - Integer promotion - Phobos names (cryptic, completely different from other languages) - Autodecoding - Foreach_reverse (useless) - Two mechanism for foreach (opApply & popFront) - Traits as a library - Real (D standardised primitive types, but here it comes with a machine dependent one) - ff as init value for chars - Dub as package manager - Unqualified parameter passing (if a parameter is ref, you must pass it prefixed with ref)
 * Features you'd like to see in D
- Unittest naming - Benchmarks included in language similar to unittests - Templated class/interface inheritance - Shared (truly implemented) - Cent (truly implemented) - Range concept as language built in - Safe by default - Nullable/Optional as language feature
 Ideas? Examples?

 Thanks!
Oct 15 2021
prev sibling next sibling parent bauss <jj_1337 live.dk> writes:
On Monday, 11 October 2021 at 15:59:10 UTC, Atila Neves wrote:
 * Worst features (in your opinion) in D
Finally got one for D. - Phobos always being compiled in release, regardless of whether you compile your application in release mode or not. Which leads to issues like this: https://forum.dlang.org/thread/skjrdf$2buv$1 digitalmars.com And also opens up for buffer overflow for anyone using Phobos. It's by far one of the most serious issue D has had in years.
Oct 19 2021
prev sibling next sibling parent reply Andrea Fontana <nospam example.org> writes:
On Monday, 11 October 2021 at 15:59:10 UTC, Atila Neves wrote:
 I'm brainstorming about what I'll talk about at DConf, and 
 during a conversation with Walter I thought it might be cool to 
 talk about:

 * Worst features implemented in a non-toy language
Old but still nice: https://eev.ee/blog/2012/04/09/php-a-fractal-of-bad-design/
 * Worst features (in your opinion) in D
- Every not-fully-implemented/half backed feature added prematurely.
 * Features you'd like to see in D
First thing I notice when I switch from android development: real string interpolation
Oct 20 2021
next sibling parent Imperatorn <johan_forsberg_86 hotmail.com> writes:
On Wednesday, 20 October 2021 at 08:17:48 UTC, Andrea Fontana 
wrote:
 On Monday, 11 October 2021 at 15:59:10 UTC, Atila Neves wrote:
 I'm brainstorming about what I'll talk about at DConf, and 
 during a conversation with Walter I thought it might be cool 
 to talk about:

 * Worst features implemented in a non-toy language
Old but still nice: https://eev.ee/blog/2012/04/09/php-a-fractal-of-bad-design/
 * Worst features (in your opinion) in D
- Every not-fully-implemented/half backed feature added prematurely.
 * Features you'd like to see in D
First thing I notice when I switch from android development: real string interpolation
This has been worked on several times. The community has trouble agreeing on how it should look / work it seems.
Oct 20 2021
prev sibling parent reply SealabJaster <sealabjaster gmail.com> writes:
On Wednesday, 20 October 2021 at 08:17:48 UTC, Andrea Fontana 
wrote:
 First thing I notice when I switch from android development: 
 real string interpolation
If there's one feature that shows the severe split between "BUT GC", "BUT NOGC", "BUT EASE OF USE", "BUT POWAH", "BUT PRINTF(For some ungodly reason)", "BUT BUT BUT". That one is it.
Oct 20 2021
parent reply IGotD- <nise nise.com> writes:
On Wednesday, 20 October 2021 at 08:54:17 UTC, SealabJaster wrote:
 If there's one feature that shows the severe split between "BUT 
 GC", "BUT  NOGC", "BUT EASE OF USE", "BUT POWAH", "BUT 
 PRINTF(For some ungodly reason)", "BUT BUT BUT".

 That one is it.
Why are many using D using printf to begin with and not the D equivalent like writeln?
Oct 20 2021
parent SealabJaster <sealabjaster gmail.com> writes:
On Wednesday, 20 October 2021 at 09:32:15 UTC, IGotD- wrote:
 Why are many using D using printf to begin with and not the D 
 equivalent like writeln?
In the case of the string interpolation DIP, from what I remember it was mostly Walter was very adamant on string interpolation being printf compatible. In the general case, I assume people using `printf` are mostly GC-phobic, or are just in general writing nogc code. Here's the DIP, including the links to the discussion threads: https://github.com/dlang/DIPs/blob/master/DIPs/rejected/DIP1027.md I can't be bothered myself to skim through things to pick out examples, but feel free to do so yourself.
Oct 20 2021
prev sibling next sibling parent harakim <harakim gmail.com> writes:
On Monday, 11 October 2021 at 15:59:10 UTC, Atila Neves wrote:
 I'm brainstorming about what I'll talk about at DConf, and 
 during a conversation with Walter I thought it might be cool to 
 talk about:

 * Worst features implemented in a non-toy language
 * Worst features (in your opinion) in D
 * Features you'd like to see in D

 Ideas? Examples?

 Thanks!
completely pointless in web development because it will deserialize invalid values. If you have ``` public enum Animal { Cat = 1, Dog = 2, Bird = 3 } ``` 1. You can still load a database row where the Animal value is, say, 200, and it will not give you any errors 2. You can still receive a web request for an object with property Animal Pet {get;set;} where the Animal value is 1000 and it will deserialize from JSON and create the object with a non-null Pet property like it did it correctly. When you go to use it, it will not be Cat Dog or Bird. It's so dumb. There is no advantage of using an enum over a type except when setting a value manually, which you will not be doing often in comparison to user supplied values. much a complete failure.
Oct 30 2021
prev sibling next sibling parent reply glis-glis <andreas.fueglistaler gmail.com> writes:
On Monday, 11 October 2021 at 15:59:10 UTC, Atila Neves wrote:
 * Worst features implemented in a non-toy language
Python: Assign operator meaning different things in different context `x = 3` Can mean "create a new variable x with value 3" or "assign the value 3 to variable x". This can hit you both ways, I had bugs because I misspelled a variable and created a new variable instead of assigning a new value to an existing one, and I inadvertently changed the value of an existing variable instead of creating a new one. Because of this, I am also very skeptical of Rust's "variable shadowing" feature. Python passing by reference unless it doesn't: `i=1; j=i; j+=2 ` -> i = 1, j=3 `li=[1]; lj=li; lj += [2]` -> li = [1,2], lj = [1,2]
 * Worst features (in your opinion) in D
- char[] pretends to be an array but is actually more like a linked list - lots of attributes and keywords
 * Features you'd like to see in D
- Cleaning up the attributes - Making the language simpler, not more complicated Concerning the "or" vs "||" discussion, as a non-native English speaker, I learned programming as a teenager with barely any English knowledge, and was attracted to the C/C++ syntax as it depends less on English compared to Pascal's syntax. An English-agnostic programming language would be nice to help non-native English speakers to get into programming more easily, but how would you replace keywords like "if", "while" or "for"?
Nov 01 2021
parent Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= <ola.fosheim.grostad gmail.com> writes:
On Monday, 1 November 2021 at 09:45:10 UTC, glis-glis wrote:
 An English-agnostic programming language would be nice to help 
 non-native English speakers to get into programming more 
 easily, but how would you replace keywords like "if", "while" 
 or "for"?
You could replace "if" with "?", "??" or "¿" and use "⟳" for loops. However, I've found that this makes code harder to read as you no longer get a visual separation of "numeric expressions" and the main structure of the program. This presumes that you use a regular text editor. If you create a graphical editor, you probably could use only symbols or pictures with good effect, but it is a lot of work to develop such editors.
Nov 01 2021
prev sibling next sibling parent reply Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= <ola.fosheim.grostad gmail.com> writes:
On Monday, 11 October 2021 at 15:59:10 UTC, Atila Neves wrote:
 I'm brainstorming about what I'll talk about at DConf, and 
 during a conversation with Walter I thought it might be cool to 
 talk about:

 * Worst features implemented in a non-toy language
Worst line of reasoning for not having a feature is Go that refuses to add exceptions because they don't think people will do cleanup correctly, instead you are faced with 150% more error-handling code (or code that ignore errors). Error handling in Rust also looks pretty atrocious, but I haven't written anything more than toy programs in Rust.
Nov 06 2021
parent reply Paulo Pinto <pjmlp progtools.org> writes:
On Saturday, 6 November 2021 at 11:45:18 UTC, Ola Fosheim Grøstad 
wrote:
 On Monday, 11 October 2021 at 15:59:10 UTC, Atila Neves wrote:
 I'm brainstorming about what I'll talk about at DConf, and 
 during a conversation with Walter I thought it might be cool 
 to talk about:

 * Worst features implemented in a non-toy language
Worst line of reasoning for not having a feature is Go that refuses to add exceptions because they don't think people will do cleanup correctly, instead you are faced with 150% more error-handling code (or code that ignore errors). Error handling in Rust also looks pretty atrocious, but I haven't written anything more than toy programs in Rust.
Go has exceptions, although they don't call them as such (panic/recover). Rust error handling is not easy by default, however there are some helper libraries to make it easier to do rail oriented programming, and they are in the process of adding vocabulary types for improved error handling, based on the experience of those libraries.
Nov 06 2021
next sibling parent reply Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= <ola.fosheim.grostad gmail.com> writes:
On Saturday, 6 November 2021 at 19:13:11 UTC, Paulo Pinto wrote:
 Go has exceptions, although they don't call them as such 
 (panic/recover).
They discourage using it for regular errors, and Go programmers seem to swallow the very noice error-checking regime. Panic recover is also quite clunky and runtime dependent. Yes, I personally use it as clunky hack to emulate exceptions, but it is much less maintainable.
 programming, and they are in the process of adding vocabulary 
 types for improved error handling, based on the experience of 
 those libraries.
Are they extending the language?
Nov 06 2021
next sibling parent Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= <ola.fosheim.grostad gmail.com> writes:
On Saturday, 6 November 2021 at 19:36:19 UTC, Ola Fosheim Grøstad 
wrote:
 On Saturday, 6 November 2021 at 19:13:11 UTC, Paulo Pinto wrote:
 Go has exceptions, although they don't call them as such 
 (panic/recover).
They discourage using it for regular errors, and Go programmers seem to swallow the very noice error-checking regime. Panic
I meant "very noisy"…
Nov 06 2021
prev sibling parent Paulo Pinto <pjmlp progtools.org> writes:
On Saturday, 6 November 2021 at 19:36:19 UTC, Ola Fosheim Grøstad 
wrote:
 On Saturday, 6 November 2021 at 19:13:11 UTC, Paulo Pinto wrote:
 Go has exceptions, although they don't call them as such 
 (panic/recover).
They discourage using it for regular errors, and Go programmers seem to swallow the very noice error-checking regime. Panic recover is also quite clunky and runtime dependent. Yes, I personally use it as clunky hack to emulate exceptions, but it is much less maintainable.
 programming, and they are in the process of adding vocabulary 
 types for improved error handling, based on the experience of 
 those libraries.
Are they extending the language?
Have a look here, https://blog.rust-lang.org/inside-rust/2021/07/01/What-the-error-handling-project-group-is-working-towards.html
Nov 06 2021
prev sibling parent reply Atila Neves <atila.neves gmail.com> writes:
On Saturday, 6 November 2021 at 19:13:11 UTC, Paulo Pinto wrote:
 On Saturday, 6 November 2021 at 11:45:18 UTC, Ola Fosheim 
 Grøstad wrote:
 On Monday, 11 October 2021 at 15:59:10 UTC, Atila Neves wrote:
 I'm brainstorming about what I'll talk about at DConf, and 
 during a conversation with Walter I thought it might be cool 
 to talk about:

 * Worst features implemented in a non-toy language
Worst line of reasoning for not having a feature is Go that refuses to add exceptions because they don't think people will do cleanup correctly, instead you are faced with 150% more error-handling code (or code that ignore errors). Error handling in Rust also looks pretty atrocious, but I haven't written anything more than toy programs in Rust.
Go has exceptions, although they don't call them as such (panic/recover). Rust error handling is not easy by default, however there are some helper libraries to make it easier to do rail oriented programming, and they are in the process of adding vocabulary types for improved error handling, based on the experience of those libraries.
I thought Rust error handling wasn't easy by default until they added the ? operator, at which point it became like exceptions but better. To me that was always the issue with error handling without exceptions - how to easily just propagate it up (nearly always what one wants to do). I think they nailed it.
Nov 08 2021
parent reply Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= <ola.fosheim.grostad gmail.com> writes:
On Monday, 8 November 2021 at 14:08:32 UTC, Atila Neves wrote:
 I thought Rust error handling wasn't easy by default until they 
 added the ? operator, at which point it became like exceptions 
 but better.
Looks like syntactical sugar to me, but I am no Rust expert. It means you now loose context, and how do you log?
 To me that was always the issue with error handling without 
 exceptions - how to easily just propagate it up (nearly always 
 what one wants to do). I think they nailed it.
For simple situations maybe, but it looks like a hack, as far as I can tell from the docs.
Nov 08 2021
next sibling parent reply bauss <jj_1337 live.dk> writes:
On Monday, 8 November 2021 at 14:23:15 UTC, Ola Fosheim Grøstad 
wrote:
 On Monday, 8 November 2021 at 14:08:32 UTC, Atila Neves wrote:
 I thought Rust error handling wasn't easy by default until 
 they added the ? operator, at which point it became like 
 exceptions but better.
Looks like syntactical sugar to me, but I am no Rust expert. It means you now loose context, and how do you log?
It propagates the error to the caller, so you don't lose context, as the error still needs to be handled somewhere, you just don't explicitly have to return the error from your function etc. If you need to log the error at the specific location etc. then you just don't use the ? operator. If the same mechanic existed in D then it would be something like: ```d Result!(int,Error) bar(); Result!(int,Error) foo(int x) { auto i = bar()?; return result(i * x); } void main() { auto r = foo(10); if (r.error) { // Error ... } else { writeln(r.value); } } ``` Which would translate to: ```d Result!(int,Error) bar(); Result!(int,Error) foo(int x) { auto r = bar(); if (r.error) return r; auto i = r.value; return result(i * x); } void main() { auto r = foo(10); if (r.error) { // Error ... } else { writeln(r.value); } } ``` Of course the if statements would be using pattern matching for Ok and Error, which it does in Rust. But felt lazy.
Nov 09 2021
parent reply Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= <ola.fosheim.grostad gmail.com> writes:
On Tuesday, 9 November 2021 at 10:58:34 UTC, bauss wrote:
 On Monday, 8 November 2021 at 14:23:15 UTC, Ola Fosheim Grøstad 
 wrote:
 On Monday, 8 November 2021 at 14:08:32 UTC, Atila Neves wrote:
 I thought Rust error handling wasn't easy by default until 
 they added the ? operator, at which point it became like 
 exceptions but better.
Looks like syntactical sugar to me, but I am no Rust expert. It means you now loose context, and how do you log?
It propagates the error to the caller, so you don't lose context, as the error still needs to be handled somewhere, you just don't explicitly have to return the error from your function etc. If you need to log the error at the specific location etc. then you just don't use the ? operator.
As a library author you don't know what the application is interested in. Anyway, they are working on retaining context, so the Rust developers apparently see this as being an issue. If you can only use "?" in one location without loosing context that basically establishes it as being the quick hack it looks like (by reading the docs).
Nov 09 2021
parent bauss <jj_1337 live.dk> writes:
On Tuesday, 9 November 2021 at 11:09:07 UTC, Ola Fosheim Grøstad 
wrote:
 On Tuesday, 9 November 2021 at 10:58:34 UTC, bauss wrote:
 On Monday, 8 November 2021 at 14:23:15 UTC, Ola Fosheim 
 Grøstad wrote:
 On Monday, 8 November 2021 at 14:08:32 UTC, Atila Neves wrote:
 I thought Rust error handling wasn't easy by default until 
 they added the ? operator, at which point it became like 
 exceptions but better.
Looks like syntactical sugar to me, but I am no Rust expert. It means you now loose context, and how do you log?
It propagates the error to the caller, so you don't lose context, as the error still needs to be handled somewhere, you just don't explicitly have to return the error from your function etc. If you need to log the error at the specific location etc. then you just don't use the ? operator.
As a library author you don't know what the application is interested in. Anyway, they are working on retaining context, so the Rust developers apparently see this as being an issue. If you can only use "?" in one location without loosing context that basically establishes it as being the quick hack it looks like (by reading the docs).
Yeah, it's definitely a quick hack. It was added to just remove the verbosity that you had otherwise.
Nov 09 2021
prev sibling parent reply Atila Neves <atila.neves gmail.com> writes:
On Monday, 8 November 2021 at 14:23:15 UTC, Ola Fosheim Grøstad 
wrote:
 On Monday, 8 November 2021 at 14:08:32 UTC, Atila Neves wrote:
 I thought Rust error handling wasn't easy by default until 
 they added the ? operator, at which point it became like 
 exceptions but better.
Looks like syntactical sugar to me, but I am no Rust expert.
Correct, but then again, anything other than machine code is syntatical sugar. So is `throw new Exception("oh noes");`
 It means you now loose context
I don't see how.
 and how do you log?
The same way in pretty much any and all programs written that handles exceptions - some outer loop, possibly in the main function.
 To me that was always the issue with error handling without 
 exceptions - how to easily just propagate it up (nearly always 
 what one wants to do). I think they nailed it.
For simple situations maybe, but it looks like a hack, as far as I can tell from the docs.
I disagree. To me, it has all the convenience of exceptions with none of the drawbacks.
Nov 09 2021
next sibling parent reply Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= <ola.fosheim.grostad gmail.com> writes:
On Tuesday, 9 November 2021 at 11:37:49 UTC, Atila Neves wrote:
 Correct, but then again, anything other than machine code is 
 syntatical sugar. So is `throw new Exception("oh noes");`
No, syntactical sugar has nothing to do with the machine. It is sugar if it can be fully/easily replaced by other language constructs with no semantic/typing changes. You technically can totally restructure a program with exceptions to one without, it is a rather comprehensive transformation. You usually treat exceptions as a separate construct when reasoning about the type system.
 It means you now loose context
I don't see how.
In D you can throw a wide variety of exceptions and propagate them without even knowing that they were thrown. D even retains the exception chain… (perhaps too much context for most use cases). Clearly you loose context by "?" in comparison? Python also allows you to trace the stack… that is a lot of context…
Nov 09 2021
parent reply Atila Neves <atila.neves gmail.com> writes:
On Tuesday, 9 November 2021 at 13:26:20 UTC, Ola Fosheim Grøstad 
wrote:
 On Tuesday, 9 November 2021 at 11:37:49 UTC, Atila Neves wrote:
 It means you now loose context
I don't see how.
In D you can throw a wide variety of exceptions and propagate them without even knowing that they were thrown. D even retains the exception chain… (perhaps too much context for most use cases). Clearly you loose context by "?" in comparison? Python also allows you to trace the stack… that is a lot of context…
If there are no exceptions and one is returning regular values, then the call stack is... the call stack. Given that "?" returns the original failure with whatever extra data it had, I really don't see what the difference is.
Nov 09 2021
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 09.11.21 16:39, Atila Neves wrote:
 On Tuesday, 9 November 2021 at 13:26:20 UTC, Ola Fosheim Grøstad wrote:
 On Tuesday, 9 November 2021 at 11:37:49 UTC, Atila Neves wrote:
 It means you now loose context
I don't see how.
In D you can throw a wide variety of exceptions and propagate them without even knowing that they were thrown. D even retains the exception chain… (perhaps too much context for most use cases). Clearly you loose context by "?" in comparison? Python also allows you to trace the stack… that is a lot of context…
If there are no exceptions and one is returning regular values, then the call stack is... the call stack. Given that "?" returns the original failure with whatever extra data it had, I really don't see what the difference is.
Having a stack trace with line numbers is a big deal in case the exception was unexpected.
Nov 09 2021
parent reply Atila Neves <atila.neves gmail.com> writes:
On Tuesday, 9 November 2021 at 16:44:50 UTC, Timon Gehr wrote:
 On 09.11.21 16:39, Atila Neves wrote:
 On Tuesday, 9 November 2021 at 13:26:20 UTC, Ola Fosheim 
 Grøstad wrote:
 [...]
If there are no exceptions and one is returning regular values, then the call stack is... the call stack. Given that "?" returns the original failure with whatever extra data it had, I really don't see what the difference is.
Having a stack trace with line numbers is a big deal in case the exception was unexpected.
Good point. I hadn't thought of that.
Nov 09 2021
parent Dukc <ajieskola gmail.com> writes:
On Tuesday, 9 November 2021 at 17:16:52 UTC, Atila Neves wrote:
 Having a stack trace with line numbers is a big deal in case 
 the exception was unexpected.
Good point. I hadn't thought of that.
Not a big deal IMO. Stack traces are not the main feature of exceptions anyway. Now granted that the error is a bit harder to track down without the stack trace but we don't put stack traces to `null`s or `NaN`s either. We insert logging statements separately if we want to prepare for tracking an unexpected bug.
Nov 09 2021
prev sibling parent arco <qva6y4sqi relay.firefox.com> writes:
On Tuesday, 9 November 2021 at 11:37:49 UTC, Atila Neves wrote:
 On Monday, 8 November 2021 at 14:23:15 UTC, Ola Fosheim Grøstad 
 wrote:
 On Monday, 8 November 2021 at 14:08:32 UTC, Atila Neves wrote:
 I thought Rust error handling wasn't easy by default until 
 they added the ? operator, at which point it became like 
 exceptions but better.
Looks like syntactical sugar to me, but I am no Rust expert.
Correct, but then again, anything other than machine code is syntatical sugar. So is `throw new Exception("oh noes");`
 It means you now loose context
I don't see how.
 and how do you log?
The same way in pretty much any and all programs written that handles exceptions - some outer loop, possibly in the main function.
 To me that was always the issue with error handling without 
 exceptions - how to easily just propagate it up (nearly 
 always what one wants to do). I think they nailed it.
For simple situations maybe, but it looks like a hack, as far as I can tell from the docs.
I disagree. To me, it has all the convenience of exceptions with none of the drawbacks.
Actually, Rust also has exceptions but like Go, it's ashamed to admit it: https://doc.rust-lang.org/std/panic/fn.catch_unwind.html It's supposed to be used only for unrecoverable runtime errors (panics in Rust parlance).
Nov 23 2021
prev sibling next sibling parent forkit <forkit gmail.com> writes:
On Monday, 11 October 2021 at 15:59:10 UTC, Atila Neves wrote:
 I'm brainstorming about what I'll talk about at DConf, and 
 during a conversation with Walter I thought it might be cool to 
 talk about:

 * Worst features implemented in a non-toy language
 * Worst features (in your opinion) in D
 * Features you'd like to see in D

 Ideas? Examples?

 Thanks!
I'd say being able to do the same thing, multiple ways. IMO. It's the worst feature, and yet, it's also the best feature.
Nov 09 2021
prev sibling next sibling parent reply bauss <jj_1337 live.dk> writes:
On Monday, 11 October 2021 at 15:59:10 UTC, Atila Neves wrote:
 I'm brainstorming about what I'll talk about at DConf, and 
 during a conversation with Walter I thought it might be cool to 
 talk about:

 * Worst features implemented in a non-toy language
 * Worst features (in your opinion) in D
 * Features you'd like to see in D

 Ideas? Examples?

 Thanks!
I don't think I've answered yet, even tho I have responded to a couple others. I don't really have many things to add that others haven't said but I just have this one thing to say:
 * Worst features (in your opinion) in D
The way D solves problems is by adding new features (such as attributes etc.) - but what ends up happening is that each problem solved by adding a new feature, introduces a new set of problems; often the old problem isn't even fixed properly either because the new feature is either a) not implemented entirely b) not working as intended - and then we somehow ends up with a new feature to fix the new feature. It's an endless loop that D has put itself into. I'm not sure if it can be fixed, nor am I even sure that I could think of a way to fix it. Which brings me to:
 * Features you'd like to see in D
I'd like to see everything currently in D finished, instead of introducing new features. Sometimes less is more.
Nov 15 2021
parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Mon, Nov 15, 2021 at 02:23:03PM +0000, bauss via Digitalmars-d wrote:
[...]
 * Features you'd like to see in D
I'd like to see everything currently in D finished, instead of introducing new features. Sometimes less is more.
+1. We've a lot of unfinished/incomplete things: shared, std.experimental.allocator, etc.. It's more fun to implement new things, but *somebody* has to do the grunt work of polishing what's already there. T -- Once bitten, twice cry...
Nov 15 2021
prev sibling next sibling parent Q. Schroll <qs.il.paperinik gmail.com> writes:
* Worst features implemented in a non-toy language?
* Worst features (in your opinion) in D
* Features you'd like to see in D

Undisputed first place: Reference types (ptrs, function ptrs, 
arrays, classes, etc.) are nullable by default in Java and many 
others, including D. D could have had `int*` and `int*?`, `int 
function()` and `int function?()`, `int[]` and `int[]?`, `Object` 
and `Object?`.

`std.typecons.Nullable` is basically a type constructor, and 
faking one via templates only works half-way (for example, 
`const(int)?` and `const(int?)` are the same type). 
Distinguishing nullable types is very useful documentation-wise. 
If you do this, enable nullable for every type, even if `int?` is 
implemented by a plain bool-int pair.

For me, second place for bad D feature: function types. Not 
function *pointer* types but mere function types. They aren't 
even documented, so it's technically a bug that they exist.

---

A few other nuisances that are just unnecessary to work around 
and have absolutely no justification existing:
1. Cannot initialize an empty AA by `[ ]`. Especially a nuisances 
when wanting to pass an empty AA as an argument to a function.
2. The `new` keyword is needed to allocate class objects. Makes 
meta-programming annoying, and one cannot have a literal pointer 
like `new int(1)` for, say, `Object`.
3. One cannot express every type (not counting encapsulation, 
i.e. Voldemort types) directly: Notably, one cannot express a 
function pointer returning by reference in a function argument 
list.
Nov 15 2021
prev sibling next sibling parent reply arco <qva6y4sqi relay.firefox.com> writes:
 * Worst features implemented in a non-toy language
* C: zero-terminated strings * Python 3: Metaclasses (they violate the philosophy of Python that code should be explicit, obvious and not "clever") * C++: where to start... * Java: the int/Integer (and similar) duality, made even worse by automatic boxing/unboxing * Still Java: Generic types erasure
 * Worst features (in your opinion) in D
I never really used D for anything beyond simple toy programs, but from reading about it it doesn't seem to have any truly egregious features as such apart from autodecoding. The main problem that I see is that everything is kind of half-baked, unfinished, features get added in a pursuit of the Great-Opportunity-of-the-week but they don't work coherently together.
Nov 23 2021
parent reply zjh <fqbqrr 163.com> writes:
On Wednesday, 24 November 2021 at 06:28:35 UTC, arco wrote:

The funniest part is that it's often not the deep users of D who 
say D is bad.
Nov 23 2021
next sibling parent arco <qva6y4sqi relay.firefox.com> writes:
On Wednesday, 24 November 2021 at 06:48:12 UTC, zjh wrote:
 On Wednesday, 24 November 2021 at 06:28:35 UTC, arco wrote:

 The funniest part is that it's often not the deep users of D 
 who say D is bad.
Well... Bubble, echo chamber, baby duck syndrome and all that. When people are not heavy users of D, there may often have a reason. Many language communities actively listen to what the critics say and often try to acknowledge or even address the issues. If Dlang just wants to dismiss criticism as being irrelevant because it comes from someone who doesn't really use D, then all that will achieve is that 10 years from now there will still be threads "Why is D not popular?" ;)
Nov 23 2021
prev sibling parent zjh <fqbqrr 163.com> writes:
On Wednesday, 24 November 2021 at 06:48:12 UTC, zjh wrote:

 The funniest part is that it's often not the deep users of D 
 who say D is bad.
Brags about other languages, and is critical of D. Bad money drives out `good` money.
Nov 23 2021
prev sibling next sibling parent reply Igor <stojkovic.igor gmail.com> writes:
On Monday, 11 October 2021 at 15:59:10 UTC, Atila Neves wrote:
 * Worst features implemented in a non-toy language
 * Worst features (in your opinion) in D
I am a bit late to this party :) but after reading all 29 pages of it I would say most of it is said except this one thing: I hate language constructs that go in opposite order from my thoughts making me type something then having to navigate back to add another thing. Best example for this is casting in any language. I always have to write cast operator before the thing I am casting yet in my head I never think "then I need to cast to int the variable X that I want to add". I think more like "Then I need to add variable X but I have to cast it to int".
Dec 17 2021
next sibling parent reply Tejas <notrealemail gmail.com> writes:
On Friday, 17 December 2021 at 13:14:50 UTC, Igor wrote:
 On Monday, 11 October 2021 at 15:59:10 UTC, Atila Neves wrote:
 * Worst features implemented in a non-toy language
 * Worst features (in your opinion) in D
I am a bit late to this party :) but after reading all 29 pages of it I would say most of it is said except this one thing: I hate language constructs that go in opposite order from my thoughts making me type something then having to navigate back to add another thing. Best example for this is casting in any language. I always have to write cast operator before the thing I am casting yet in my head I never think "then I need to cast to int the variable X that I want to add". I think more like "Then I need to add variable X but I have to cast it to int".
You must love the `to` template in `std.conv` then :P
Dec 17 2021
parent reply user1234 <user1234 12.de> writes:
On Friday, 17 December 2021 at 13:33:00 UTC, Tejas wrote:
 On Friday, 17 December 2021 at 13:14:50 UTC, Igor wrote:
 On Monday, 11 October 2021 at 15:59:10 UTC, Atila Neves wrote:
 [...]
I am a bit late to this party :) but after reading all 29 pages of it I would say most of it is said except this one thing: I hate language constructs that go in opposite order from my thoughts making me type something then having to navigate back to add another thing. Best example for this is casting in any language. I always have to write cast operator before the thing I am casting yet in my head I never think "then I need to cast to int the variable X that I want to add". I think more like "Then I need to add variable X but I have to cast it to int".
You must love the `to` template in `std.conv` then :P
That's indeed a good way to have cast as postfix expressions except that `to` is more than cast, as it also checks for overflow and can throw.
Dec 17 2021
parent Tejas <notrealemail gmail.com> writes:
On Friday, 17 December 2021 at 17:50:25 UTC, user1234 wrote:
 On Friday, 17 December 2021 at 13:33:00 UTC, Tejas wrote:
 On Friday, 17 December 2021 at 13:14:50 UTC, Igor wrote:
 [...]
You must love the `to` template in `std.conv` then :P
That's indeed a good way to have cast as postfix expressions except that `to` is more than cast, as it also checks for overflow and can throw.
Those are not good things?
Dec 17 2021
prev sibling next sibling parent Rumbu <rumbu rumbu.ro> writes:
On Friday, 17 December 2021 at 13:14:50 UTC, Igor wrote:
 On Monday, 11 October 2021 at 15:59:10 UTC, Atila Neves wrote:
 * Worst features implemented in a non-toy language
 * Worst features (in your opinion) in D
I am a bit late to this party :) but after reading all 29 pages of it I would say most of it is said except this one thing: I hate language constructs that go in opposite order from my thoughts making me type something then having to navigate back to add another thing. Best example for this is casting in any language. I always have to write cast operator before the thing I am casting yet in my head I never think "then I need to cast to int the variable X that I want to add". I think more like "Then I need to add variable X but I have to cast it to int".
In sql you can write ```cast(field as type)```. semantics are not 100% equivalent to the usual cast operator ().
Dec 17 2021
prev sibling parent Quirin Schroll <qs.il.paperinik gmail.com> writes:
On Friday, 17 December 2021 at 13:14:50 UTC, Igor wrote:
 I hate language constructs that go in opposite order from my 
 thoughts making me type something then having to navigate back 
 to add another thing. Best example for this is casting in any 
 language. I always have to write cast operator before the thing 
 I am casting yet in my head I never think "then I need to cast 
 to int the variable X that I want to add". I think more like 
 "Then I need to add variable X but I have to cast it to int".
I feel the same about writing. But you have to consider how code as TargetType` there. In D, you can do the same: ```D auto ref TargetType as(TargetType, SourceType)(auto ref SourceType object) { return cast(TargetType) object; } auto result = fun(x.as!int).as!string; ``` I'll agree that an operator would look nicer, but – as is more often than not the case with D – if a library solution is found that isn't horrible, the probability that the language will be extended is around 0.
Dec 18 2021
prev sibling next sibling parent Era Scarecrow <rtcvb32 yahoo.com> writes:
On Monday, 11 October 2021 at 15:59:10 UTC, Atila Neves wrote:
 * Worst features implemented in a non-toy language
I did some programming at a tech company in 2011, and was introduced to ASP. The default in the webpage-based language was variables were passed around using reference. This of course turns the whole programming understanding on it's head because you assume you pass copies of native types or copy structs to the stack and you can't affect the original variables (unless you intend to or they are classes passed around). So to get around to expected normal behavior you have to put ByVal everywhere on all arguments.
Dec 28 2021
prev sibling next sibling parent reply data pulverizer <data.pulverizer gmail.com> writes:
On Monday, 11 October 2021 at 15:59:10 UTC, Atila Neves wrote:
 I'm brainstorming about what I'll talk about at DConf, and 
 during a conversation with Walter I thought it might be cool to 
 talk about:

 * Worst features implemented in a non-toy language
 * Worst features (in your opinion) in D
 * Features you'd like to see in D

 Ideas? Examples?

 Thanks!
For me there are two main ones: * A lot of people have said this one but I'll +1 it. Tuples fully built into the language with destructuring and all the common features. A year or two ago I thought this was definitely going to happen. * Relaxing policy on symbolic and infix/prefix/postfix/binary/unary notation, perhaps having protections against using obvious things like "." but relatively free elsewhere. From a science/math point of view this would be great, and it can greatly improve code readability in such applications.
Dec 29 2021
parent data pulverizer <data.pulverizer gmail.com> writes:
On Wednesday, 29 December 2021 at 20:07:20 UTC, data pulverizer 
wrote:
 For me there are two main ones:

 * A lot of people have said this one but I'll +1 it. Tuples 
 fully built into the language with destructuring and all the 
 common features. A year or two ago I thought this was 
 definitely going to happen.

 * Relaxing policy on symbolic and 
 infix/prefix/postfix/binary/unary notation, perhaps having 
 protections against using obvious things like "." but 
 relatively free elsewhere. From a science/math point of view 
 this would be great, and it can greatly improve code 
 readability in such applications.
One more thing, native string interpolation similar to f-strings style in Python or Julia style strings for example ``` auto my_variable = 42; auto output = "The meaning of life is ${my_variable}" ``` I think this also seemed like it was in the works a year or two ago.
Jan 08 2022
prev sibling parent reply sighoya <sighoya gmail.com> writes:
On Monday, 11 October 2021 at 15:59:10 UTC, Atila Neves wrote:
 * Worst features implemented in a non-toy language
- C Preprocessor - C Macros - Error handling through return codes - Languages with undecidable grammar
 * Worst features (in your opinion) in D
- I need more time for this to find ones, but mostly it is the half backedness of features
 * Features you'd like to see in D
- structs implementing interfaces - autoboxing structs to interfaces - faster, easier and more powerful CTFE, I think this will come with newCTFE - runtime templates/runtime reflection (not as default, but as an option) I'm unsure about type classes/protocols/concepts/traits, they are, theoretically, clearly superior to OOP, but as we already have classes & interfaces in D, they would be too overlapping, I think.
Apr 23 2022
parent rikki cattermole <rikki cattermole.co.nz> writes:
On 24/04/2022 3:01 AM, sighoya wrote:
 I'm unsure about type classes/protocols/concepts/traits, they are, 
 theoretically, clearly superior to OOP, but as we already have classes & 
 interfaces in D, they would be too overlapping, I think.
Signatures are OOP. Its just that the relationship is inverse of class/interface.
Apr 23 2022