Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make new optional #20750

Closed
Zectbumo opened this issue Aug 29, 2014 · 42 comments
Closed

Make new optional #20750

Zectbumo opened this issue Aug 29, 2014 · 42 comments
Labels
area-language New language issues should be filed at https://github.com/dart-lang/language customer-flutter type-enhancement A request for a change that isn't a bug

Comments

@Zectbumo
Copy link

Zectbumo commented Aug 29, 2014

I see how new makes it familiar to new programmers but the new keyword is really not necessary in the end. Dart has named constructors and static methods and it is up to the library maker to decide which is appropriate to use. Currently named constructors need `new' while static methods do not. My focus here is to relieve the programmer of having to remember what side of the bed the library developer woke up on and remembering do I need the new keyword or not.

Story time:
One day a library developer woke up and said parsing ints from strings is "discovering" the int so therefore it is not a constructor and a static method instead: Integer.parse(); was born. The library user MUST NOT use new to construct this Integer. Then another morning a library developer makes Element.html() and this time he think this is a constructor. The library user MUST use new to create his Element. This requires the library user to stop and think, do I need new or not?, when really in the end the library user just wants an object created; it doesn't matter how it's made.

Before:

var now = new DateTime.now();
var num = Integer.parse('54');
var elm = new Element.html(<u>54&lt;/u&gt;');

After (optional):

var now = DateTime.now();
var num = Integer.parse('54');
var elm = Element.html('<u>54</u>');

A discussion in issue #18241 talks about making const and new together being optional. This issue was created to focus on just making the new keyword optional.

@DartBot
Copy link

DartBot commented Aug 29, 2014

This comment was originally written by @zoechi


What about cases without a named constructor or do you propose to use only named constructors?
var car = Car.new(); // rather ugly in my opinion.

@DartBot
Copy link

DartBot commented Aug 29, 2014

This comment was originally written by norman...@gmail.com


'new' makes it clear that we instantiate new object, not referencing to existing variable.

@Zectbumo
Copy link
Author

…do you propose to use only named constructors?
var car = Car.new(); // rather ugly in my opinion.

No. Nameless constructors are fine the way they are.

What about cases without a named constructor…

For consistency sake I would say make new optional there as well.

var buf = new StringBuffer();
or
var buf = StringBuffer();

I think it's pretty clear what is going on here. Even if new is made to be required in the nameless constructor case and optional in the named case then I would understand. I leave it in your hands to make the call.

@DartBot
Copy link

DartBot commented Aug 30, 2014

This comment was originally written by @Emasoft


Please don't. That would make the code much less readable. You would not be able to distinguish methods calls from class instantiations anymore.
Also using static constructors give no advantage at all.
You have to type the same number of characters for:

var car = Car.new();
or
var car = new Car();

It is completely useless, and it would drastically reduce readability of code.

@DartBot
Copy link

DartBot commented Aug 30, 2014

This comment was originally written by @richardeakin


Please don't. That would make the code much less readable. You would not be able to distinguish methods >> calls from class instantiations anymore.

In other languages that don't require the new keyword to make an object, like C++, python, and newer language's like Apple's swift, method calls and class instantiation is completely distinguishable. The reason is simply that the way you write the code makes it clear (method names start with lower case, classes start with upper case). In all practicality, this is all the information you need to determine when a new object is constructed, as 98% (or more) of all code out there follows by this simple style rule.

I'll even go as far as to say that it really doesn't matter anyway, I've never had a problem with 'knowing where something was originally constructed' using the C++ standard library (constructors look_like_this()), methods can always return a newly constructed object and you would not know at the call site. If one is worrying about something like where objects are constructed, there are probably much larger things wrong with the structure of their codebase.

@anders-sandholm
Copy link
Contributor

Added Area-Language, Triaged labels.

@DartBot
Copy link

DartBot commented Sep 1, 2014

This comment was originally written by nino.porcino...@gmail.com


if 'new' is made optional, then also 'const' (from constant constructors) should be optional too. The semantic should be:

var p = Point(); // alias for var p = new Point(); if Point is normal constructor
var p = Point(); // alias for var p = const Point(); if Point is const constructor

@Zectbumo
Copy link
Author

Zectbumo commented Sep 1, 2014

if 'new' is made optional, then also 'const'

No, optional const has it's own issues. See issue #18241

@Zectbumo
Copy link
Author

Zectbumo commented Sep 1, 2014

If the use of new is important to you then it should be an entry in your style guide to prefer new.

@lrhn
Copy link
Member

lrhn commented Sep 1, 2014

Since we have factory constructors, there really is no functional distinction between:

class C { factory C.foo() => expr; }

and

class C { static C foo() => expr; }

Constructors are intended to be a recognizable way to get objects of a type. If I want a Foo, I'll look at Foo constructors to see which one I can use.
I could just as well be looking at static functions that return Foo.

The reason factory constructors exists is that if you use a constructor, then the call points use "new", and then you can't replace the constructor with a static function. If there hadn't been a "new" operator, and being a constructor was a property of a method, not of its usage, then there would be no need for factory constructors.

(By extension, a feature that makes sense for factory constructors, like being a delegating factory constructor, could just as well apply to all static methods).

@DartBot
Copy link

DartBot commented Sep 1, 2014

This comment was originally written by @seaneagan


Constructors are intended to be a recognizable way to get objects of a type. If I want a Foo, I'll look at Foo constructors to see which one I can use. I could just as well be looking at static functions that return Foo.

Yep, the api doc tool could even consider those to be "Constructors" and group them for the user. With the current setup if the api user needs to first look through the constructors and static methods to determine all the ways to create an instance, and they need to remember which category each falls into rather than just remembering the name.

The reason factory constructors exists is that if you use a constructor, then the call points use "new", and then you can't replace the constructor with a static function.

But as an api user there's nothing that guarantees me that the api author won't refactor to a static method, if new were optional then api authors can omit it to protect themselves from such a refactoring. And same goes for the reverse refactoring from static method to refactoring, an optional new would protect users from that as well.

If there hadn't been a "new" operator, and being a constructor was a property of a method, not of its usage, then there would be no need for factory constructors.

Of course we would need generic methods (issue #254) for that, which would be great to have anyways. And there would need to be a way to create an unnamed static method, which wouldn't be too difficult to come up with a declaration syntax for.

@DartBot
Copy link

DartBot commented Sep 2, 2014

This comment was originally written by @Emasoft


A programming language must be EXPRESSIVE. Because if it is not, it is not easily readable. And if it is not easily readable it is much more difficult to learn, much more difficult to find errors in the code causing bugs, and much more difficult to integrate the code written by other developers and to understand how it works. Being EXPRESSIVE is now considered a major feature of a language. And:

var car = Car();

is less expressive than:

var car = new Car();

because just reading the former I cannot infer if Car() is a Method or a Class, while if I read the latter I can infer that Car() is a Class at a glance.

This is why using the "new" keyword is so much better than not using it. There are other possible advantages, but this is the main one.

@Zectbumo
Copy link
Author

Zectbumo commented Sep 2, 2014

because just reading the former I cannot infer if Car() is a Method or a Class

Incorrect, you can infer Car is a class because the C is capitalized.

@DartBot
Copy link

DartBot commented Sep 2, 2014

This comment was originally written by @richardeakin


because just reading the former I cannot infer if Car() is a Method or a Class

Incorrect, you can infer Car is a class because the C is capitalized.

I agree, and moreover you really don't need to know whether the method is a constructor or a class - you just need to know that it returns a new variable of type Car.

I believe the use of new keyword is more familiar to those who have had the habit engrained into them by working with java, javascript, or c# for a long time. Many others find the following statements much more expressive:

var pt = Point( 2, 3 ) + Point( 4, 5 ) + Point( 6, 7 );

as compared to what is currently required (and appears to only be for stylistic and habitual reasons):

var pt = new Point( 2, 3 ) + new Point( 4, 5 ) + new Point( 6, 7 );

Honestly, when I was reading response #­12, I thought he/she was going to be in favor of making new optional until he/she began writing example code!

About expressiveness, I think it is more than just being readable - it is also about being able to efficiently code your thoughts. I think writing new 3 times in one line hinders this goal, IMO.

@DartBot
Copy link

DartBot commented Sep 2, 2014

This comment was originally written by @richardeakin


Sorry for typos, meant to write:

"...you really don't need to know whether Car() is a method or class constructor..."

Anyway point being, it returns a variable that didn't exist before that line, that is sufficient.

@DartBot
Copy link

DartBot commented Sep 3, 2014

This comment was originally written by @Emasoft


Incorrect, you can infer Car is a class because the C is capitalized.

Sorry to disappoint you, but in Dart there is no guarantee that a class name is capitalized, and no guarantee that a method name is not capitalized. Capitalization is not part of the Dart specifications, is not enforced by the compiler, and this practice is then completely arbitrary. I use Dart libraries with all sort of different capitalization styles. You cannot base your inference on this.

This is why you need the "new" keyword to distinguish the class from the method.

About expressiveness, I think it is more than just being readable - it is also about being able to efficiently code your thoughts. I think writing new 3 times in one line hinders this goal, IMO.

EXPRESSIVENESS is not CONCISENESS. It is just the opposite. In fact the best designed language is the one that reach the right balance between EXPRESSIVENESS and CONCISENESS.

By definition:

EXPRESSIVENESS: "The amount of information about what the code does that is explicitly expressed by the language syntax and keywords. Also referred to as verbosity."

CONCISENESS: "The amount of compactness (less number of characters needed to be typed) allowed by the language to write syntactically correct statements. Also referred to as brevity."

The former improves the amount of things you can understand reading a code statement, the latter improves the speed at which a code statement can be read (or written).
The following statement:

var pt = new Point( 2, 3 ) + new Point( 4, 5 ) + new Point( 6, 7 );

is MORE EXPRESSIVE and LESS CONCISE than:

var pt = Point( 2, 3 ) + Point( 4, 5 ) + Point( 6, 7 );

because you can infer MORE things (that you are creating some new Points objects instead of calling a Point method for example) but you need more time to read it.

In an hypotetical top EXPRESSIVE language would be like this:

define new variable ofType:Class(Point)) withName:pt = define new Class(ofType:Point)( withParameters: x:2, y:3 ) + define new Class(ofType:Point)( withParameters: x:4, y:5 ) + define new Class(ofType:Point)( withParameters: x:6, y:7 );

While that would be very expressive and clear (you will understand even if you don't know the language) that would be not CONCISE enough, because it will be slow to write and to read. This is why EXPRESSIVITY is reduced with a more CONCISE syntax:

var pt = new Point( 2, 3 ) + new Point( 4, 5 ) + new Point( 6, 7 );

This syntax is a good compromise between EXPRESSIVENESS and CONCISENESS, because it is as compact as it can be without leaving space to any ambiguity.

This other one instead:

var pt = Point( 2, 3 ) + Point( 4, 5 ) + Point( 6, 7 );

is too much CONCISE, because it is so compact that it leaves some things undefined, causing ambiguity in reading the code.

You must also consider that all modern editors have an "autocompletition" feature. This means that sometimes it is quicker to write:

new Point()

than to write:

Point()

and this is because you only need to type 'new P', then the autocompleter will show a list of Class Names beginning with 'P' to select from and press enter.
In the latter case instead when you write the letter P the autocompleter will show a list of ALL Class Names + ALL Method Names + ALL Data Fields Names, etc. that begins with the letter P to select from. A list much longer and less specific to browse, and consequently slowing down the autocompletition procedure. Autocompletition is used widely because names often need to be very long to be meaningful in modern frameworks, and typing those manually would be slower.
So in the end the use of the "new" keyword will end to be both more expressive and faster to write than his omission.

@Zectbumo
Copy link
Author

Zectbumo commented Sep 3, 2014

and this is because you only need to type 'new P'

You will still be able to type 'new P' afterwards. This proposal is to make new optional, not to remove it so your auto-completer will work just as you expect it. (no change)

In the latter case instead when you write the letter P the autocompleter will show a list of ALL Class Names + ALL Method Names + ALL Data Fields Names, etc.

False implication. When you write the letter 'P' your auto-completer will show all these in either case. The reason being is you might be referring to a static method on a class so the auto-completer will currently suggest classnames that start with the letter 'P' to complete. (again, no change)

@DartBot
Copy link

DartBot commented Sep 3, 2014

This comment was originally written by @zoechi


Requiring new because some developers are not following the Dart style guide is not a very convincing argument. I don't think new can recover much readability in such code.
If there is no hard requirement (parsing?) for new it should not be necessary.

@DartBot
Copy link

DartBot commented Sep 3, 2014

This comment was originally written by @Emasoft


False implication. When you write the letter 'P' your auto-completer will show all these in either case.

Not true. If the "new" keyword is present, the autocompleter will know that next comes a class name, and nothing else. Because only class names require "new". If the 'new' keyword is missing, the autocompleter have NO WAY to know if you are going to type a class name or a method name. And neither someone who read the statement. And that is exactly because the new keyword add an information otherwise lacking.

Requiring new because some developers are not following the Dart style guide is not a very convincing argument.

A style guide is nothing more than a suggestion if it's not enforced by the compiler. And in the real world you cannot rely on something arbitrary. Even if I always remember to follow the guidelines in my part of the code, other programmers working at the same project could not. And external Dart libraries we use on the project are often written with the more diverse styles. Those ported from javascript for example rarely use capitalized letters for classes. And nobody will assure you that in the libraries you imported there are no methods with capitalized letters with the same names of some of your project classes. You would always risks to mistake a Color() method with a Color() class. This is why a 'new' keyword is so important to have in a OO language. Removing it to save yourself the trouble of typing 3 petty characters is not worth the resulting loss of expressiveness and all the bugs deriving from it.

@Zectbumo Zectbumo added Type-Enhancement area-language New language issues should be filed at https://github.com/dart-lang/language labels Sep 3, 2014
@ahmetaa
Copy link

ahmetaa commented Oct 8, 2015

@Emasoft,

The percentage of people who do not follow the style guide for method and class names will probably be minuscule (Probably some C# programmers). So such ambiguity is tolerable. And, even then, analyzer should emit a warning so this is really not a big issue. I believe removing "new" is the way to go.

@motleytech
Copy link

[Edited with some more details]
Reading this conversation has been interesting.

I realized that some of the community really likes the new keyword and fights to retain it. I, being from the python community don't know of a good reason to have new at all... and was hoping to learn something here.

However, most of what I hear is that "its already here, and its not a big pain, so lets keep it" and "it can lead to more info if a new object is being created". The only language that needed it was C++, but definitely not needed in Java or C#.

From personal experience, I have never seen the "less info because of lack of new" problem in our 10000 file python codebase... for the simple reason that all class names are Capitalized. And pep8 / pyflakes tests automatically fail if that's not the case (I don't remember the last time that happened because someone forgot to Capitalize the class name).

Also, I was surprised to know that the new is technically not required in Java / C# or Dart.

Why did we agree to get chained to the unessential new and even more bizarre, how did we come to depend on it so much that we can't even let it become optional?

The only reason to keep new mandatory is that - it must be really really important to differentiate between instantiating a new object vs getting an object back as the result of a function call. In my opinion, that differentiation does not seem important at all.

In this article, Bruce Eckel scratches his head on why Java didn't drop the new keyword. An excerpt from the post...

Java made a point of dissing the C++ way of doing things, so the inclusion of the new keyword is a mystery. My guess, after studying decisions made in the rest of the language, is that it just never occurred to them that they could get away without it.

@Zectbumo
Copy link
Author

The new conversation is interesting and I am back to add more. I have kept this issue in the back of my mind for about a year now I have found a technical point along the way. So far the discussion has been very opinionated with weak arguments but I have been looking for an actual technical difference.

Dart:

class A {}

main() {
  var B = A;
  new B(); // [error on line 5] 'B' is not a type.
}

Javascript:

function A() {}

var B = A;
new B(); // returns instance of A. This actually works!

Dart could be using the new keyword to restrict this dynamic usage on purpose for whatever reason. The only reason I can think of is for optimization purposes since Javascript is able to do it. I can see something like this holding the language back from "simply" removing new. It would be nice to hear from someone with deep technical knowledge about this.

P.S. Just to make things clear: I'm still against the enforcement of new.

@zoechi
Copy link
Contributor

zoechi commented Nov 14, 2015

class A {}

main() {
  var B = A;
  new B(); // [error on line 5] 'B' is not a type.
}

I think this should work with dart-archive/dart_enhancement_proposals#4

@kasperpeulen
Copy link

I think this may be the way to go, especially with the new linter. For example, you could then make sure the code base always uses uppercase for classes.

I would prefer removing new keyword completely, but I think this would be better, then the current situation.

@kevmoo kevmoo removed the triaged label Mar 1, 2016
@kevmoo kevmoo added type-enhancement A request for a change that isn't a bug and removed priority-unassigned labels Mar 1, 2016
@sethladd
Copy link
Contributor

sethladd commented Dec 7, 2016

FWIW this would help Flutter code, which create a lot of new instances in build() methods.

@lenkite
Copy link

lenkite commented Jan 13, 2017

Kotlin (language for JVM) also omits the new keyword. Look at type safe builders in Kotin. They are so beautiful to work with and UI object hierarchies can be constructed with ease and readability is terrific! Dart really needs syntactic sugar here - making new optional would help a bit.

verticalLayout {
    val name = editText()
    button("Say Hello") {
        onClick { toast("Hello, ${name.text}!") }
    }
}

@floitschG floitschG mentioned this issue Jan 13, 2017
16 tasks
@floitschG
Copy link
Contributor

floitschG commented Jan 13, 2017

Optional new is an accepted feature: #27154
We are not working on it right now, but it's on our roadmap. Unfortunately, I can't give any timelines.

@hooluupog
Copy link

hooluupog commented Mar 31, 2017

Here's my two cents on the subject,

class A{
    int a;
    String b;
    A(this.a,this.b);
}
List<A> list = [new A(1,"abc"), new A(2,"abcd"),...];

After new being optional, it will be great if i can write
List<A> list = [(1,"abc"), (2,"abcd"),...];
Both 'new' and 'A' are removed(list's type is already declared, so the types 'A' on the right are redundant).

@Emasoft
Copy link

Emasoft commented Mar 31, 2017

@hooluupog What? The Dart design team already made the code unreadable enough making 'new' optional. Now you suggest to make type names optional? How the hell I'm supposed to know what this line of code means, for example?

myObject.MyMethod([(1,"abc"), (2,"abcd"),...])

Somebody is forgetting that readability and understandability of code is the MOST IMPORTANT FEATURE of a programming language. Otherwise we would all be better to keep writing in binary 010101...

@hooluupog
Copy link

hooluupog commented Apr 1, 2017

@Emasoft I do not suggest to make type names optional.In fact,I fully support strong type. What i mean is to remove unneeded redundancy. Even in Go(which is a very opinionated language),I
can write var list = []A{{1,"abc"}, {2,"abcd"},...} //A is a struct type in Go.

@Emasoft
Copy link

Emasoft commented Apr 1, 2017

@hooluupog I can still read the type in your Go example. The A is at the right side of the assignement operator. Not so in your proposal. At the right side of '=' you don't have type names anymore, and this is confusing.

Showing it at the left side is not enough. Not only I cannot use the 'var' to infer the type, but also because If I can declare a List just like you say:

List<A> list = [(1,"abc"), (2,"abcd"),...];

...then I should be able to pass the same expression to a method with the following signature:

void MyMethod(List<A> list);

..resulting in:

myObject.MyMethod([(1,"abc"), (2,"abcd"),...])

But then how I'm supposed to know what this line of code means?

Can you see what the problem is?

@lrhn
Copy link
Member

lrhn commented Apr 2, 2017

That particular shorthand is unlikely to be accepted. Apart from the lower readability, it's also ambiguous. It looks simple here because the A constructor takes two arguments, but what if it was just

List<B> list = [(x + 2)];

It's very non-obvious that you need to coerce x + 2 to B. Also, it assumes that you will use the empty-named constructor (new B(x + 2)), but there is no help in using a named constructor - if B.foo is the right one to use, this syntax doesn't allow it.
I'm more interested in explicitly omitting the class name where it's given, so maybe something like:

List<B> list = [.foo(x + 42)];

would mean that the omitted thing before the . is the expected type.

@Emasoft
Copy link

Emasoft commented Apr 2, 2017

@irhn That . is hard to spot. You can easily miss it, or type it by error. That is an even more unreadable expression.

Readability must be paramount. Do you know that on average we spend 87% of the development time debugging and looking for errors in the code and only 13% of the time actually writing the code?
After all this years there is still people (script kiddies, mostly) who think that typing less characters is cool or smart... well, I have bad a news for them: it is dumb. The dumbest thing you can do.

@zoechi
Copy link
Contributor

zoechi commented Apr 2, 2017

I don't think the . is too hard to spot (I guess better syntax ideas are always welcome though).
Also I'd expect the analyzer to generate an error in case it is typed unintentionally.

I also don't think writing less code is an important goal, but more code is more to read and redundant information, like repeated type annotations, often make code harder to read, which should be a good enough reason to try to get rid of them.

@Emasoft
Copy link

Emasoft commented Apr 4, 2017

The . is the smallest character of all, of course it is hard to spot! It is also used for MULTIPLE functions. You can have many dots one near each other, with different functions, when you use floating point numbers (0.011*-1.2/4-.A*4.21-.B*0.11-.A-.102+1.2-.A*0.1-.B-.01/.A+.3 <- try to guess if there is a dot that is not right). There is a basic language design imperative, and that is to make errors easy to spot.

@zoechi
Copy link
Contributor

zoechi commented Apr 4, 2017

It takes as many space as any other character ;-) and there are no other places where . comes before a non-numeric character, therefore I find it quite distinctive. . before numeric characters is quite seldom and usually stands out as number value. As mentioned I can imagine that there are better options, which is why I wrote "(I guess better syntax ideas are always welcome though)"
And the options are quite limited, because other symbol characters are already in use for other constructs.

@eernstg
Copy link
Member

eernstg commented Feb 20, 2018

Closing: With the feature specification on implicit creation, it has been decided that Dart will have the feature which is requested here. ;-)

For an instance creation expression (say, new C(42) or const C(42)) it is allowed to leave out the new or const keyword (yielding C(42)). The decision about whether such an expression means new ... or const ... is a little bit involved, but the main idea is that it will be const whenever possible, and otherwise new; said feature specification has the details.

Implementation of this feature is ongoing.

@eernstg eernstg closed this as completed Feb 20, 2018
@sethladd
Copy link
Contributor

Cool! is there a tracking issue for the implementation?

@eernstg
Copy link
Member

eernstg commented Feb 20, 2018

Yep: #30921. Note that the 'Specification' subtask isn't checked, but that is the language specification proper. The design has been finalized and agreed to, and it is documented in the feature specification for implicit creation. That material will later be integrated into the language specification.

@redradist
Copy link

Guys, from my point of view having "new" keyword for instance creation and without it, seems like noisy
... Because it is two different ways of creation of object ...

Will be new keyword removed in future completly ?

@lrhn
Copy link
Member

lrhn commented Aug 12, 2019

No promises. I hope it will be removed at some point, but it's a low-priority and heavily breaking change, so the cost/benefit ratio is not in its favor as a stand-alone change.

If we have another related language change, we may be able to roll the removal of new into that (if you are going to run a migration program on your code, we can remove the new for you as well).
It's probably not something we'll do as part of an otherwise unrelated language change.

@eernstg
Copy link
Member

eernstg commented Aug 12, 2019

Eliminating new completely is not obviously an improvement. If you use new e with some term e rather than e on its own then you've specified that evaluation must invoke a constructor. This is not an ironclad guarantee that it will yield a fresh object (but the exception, a factory constructor, is written knowing that it should be OK to view the returned object as fresh). So a few well chosen new keywords might be helpful for the reader of a piece of code.

A lot of valuable work has been done in the area of lints for Dart, and it seems that the community is quite happy about having support for specifying various constraints on code. The ability of the new keyword to specify a constraint on the code ("this expression builds a new object") and have tool support for verifying it makes it fit in with this trend.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-language New language issues should be filed at https://github.com/dart-lang/language customer-flutter type-enhancement A request for a change that isn't a bug
Projects
None yet
Development

No branches or pull requests