Open vbcodec opened 7 years ago
My suggestion is omitting new keyword for value type.
This makes it a lot harder to read code because you can never be sure if you are looking at a method call or a constructor call. I don't think this is worth a few saved keystrokes.
I've never liked the distinction between constructors and regular methods. It's a bit too late for this change, though.
@pdelvo This is valid point against. But lot of functions are called from other objects, and these will be distinguishable from classes in most cases. Additionally naming schemes for functions and classes usually are different, and this may be helpful to conclude if is called function or not. Beside of this, omitting is optional, so if some developer detect such ambiguity then may add `new' keyword to improve readability.
I believe this was proposed specifically for records as type invocation.
I have also seen this was proposed. For the sake of compatibility, new
keyword can be omitted only for the record types (newly added syntax) in the proposal.
On the other hand, now target-typed new
expression is proposed.
I always missing value type construction syntax of C++
Point p(0,0,0);
But I would never support omitting new
after assigning operator. That's so wrong and misleading and easily ambiguous
Look into how Python uses the __call__
method on Classes.
a = A() # executes __call__ on the class, which then calls __init__ on the instance
a() # executes __call__ on the instance
Callable instances are used for attributes, memoization, decoration, etc...
It is a powerful pattern that is more general / less verbose than C# Attribute
classes.
It may be useful to have C# callable instances in the future:
class C : ICallable
{
public int Call()
{
...
}
public static M()
{
var c = new C();
var d = c(); // executes Call()
}
}
for things like Nullable
, Lazy
initialization, etc...
In Python, the confusion between class calling and instance calling is a matter of capitalization convention. In C#, this would be less clear and would suggest keeping the new
keyword for object construction.
Other possible areas of confusion to think about:
string[] array = new string[2]; // creates array of length 2, default values
string[] array = new string[] { "A", "B" }; // creates populated array of length 2
string[] array = { "A" , "B" }; // creates populated array of length 2
(Non-)Interned strings:
string s = new String(chars);
string s2 = new StringBuilder().Append("My").Append("Test").ToString();
Boxed value types.
I would much rather have target typed new, and do:
Point p = new;
Point p = new();
Point p = new(0, 42);
@AustinBryan ICYMI, that's https://github.com/dotnet/csharplang/issues/100.
I always missing value type construction syntax of C++
Yes, well we both know this is actually the stack allocation semantics and not the "value type" semantics; but I'm just being pedantic about being semantic. 😆
Some more suggestions... new keyword could be inferred instead of being explicit
Currently Class obj = new Class();
//Suggested Class obj; Class obj(); Class obj("simple"); Class obj = null;//null, no object created
How about a using statement syntax, as a complement to the static using statement, where you can explicitly bring in types from a namespace as callable like functions. That way you opt-in to the feature:
using CSharpForMarkup;
using static new Xamarin.Forms; // static new syntax, can now call all Xamarin.Form type ctors without new keyword
using static Xamarin.Forms.LayoutOptions;
using static Xamarin.Forms.StackOrientation;
using static MyApp.Localization.Strings;
using static MyApp.Resources.Styles;
// ...
private View CreateSearchBar() =>
StackLayout
{
Orientation = Horizontal,
HorizontalOptions = FillAndExpand,
Padding = Thickness(0, 0, 0, 20),
Margin = Thickness(0),
Children = {
// parenthesis still optional, even without new keyword, using initializer syntax
Entry {
Placeholder = PartNumberPlaceholderText,
HorizontalOptions = FillAndExpand,
}.Bind(Entry.TextProperty, nameof(ViewModel.PartNumber)),
Button {
Style = ConfirmButtonStyle,
Text = GoButtonText,
}.Bind(Button.CommandProperty, nameof(ViewModel.SearchPartHistory))
}
};
I would prefer to be able to import an entire namespace, as it would get cumbersome to do so one type at a time for large libraries of types, e.g. Xamarin.Forms controls.
@JeroMiya
Saving 12 keystrokes doesn't seem like a good benefit for making the language more difficult to read and reason about.
@HalFour
I would say that I disagree with the premise of that statement. I find the resulting code easier to read and reason about, not harder. The new keyword causes syntactic clutter that is not ultimately useful and draws your attention away from the more important structures of the code.
Also C# wouldn't be the first language that lets you skip the new keyword (like Dart) or where there wasn't a syntactic distinction between constructors and other functions to begin with (Python), and it's a positive thing in those languages, in my opinion.
@JeroMiya
The new keyword causes syntactic clutter that is not ultimately useful and draws your attention away from the more important structures of the code.
And clearly specifies what the code does. It's not clutter, it's a necessary operator. Removing new
would be like removing semicolons; a massive amount of effort that results in a net-negative of productivity.
Also C# wouldn't be the first language that lets you skip the new keyword (like Dart) or where there wasn't a syntactic distinction between constructors and other functions to begin with (Python), and it's a positive thing in those languages, in my opinion.
Those languages were designed with that in mind, it wasn't bolted on later. Not that it matters at all what other languages do. Different languages have different syntax.
And clearly specifies what the code does. It's not clutter, it's a necessary operator. Removing new would be like removing semicolons; a massive amount of effort that results in a net-negative of productivity.
There's no fundamental or practical difference between a function that returns an object and a new expression that creates a new object. They're both "functions which return an object", and in this context, they're both "expressions which evaluate to an object instance". Thus, ultimately, the new keyword serves no actual purpose for the programmer in an expression tree. You could argue perhaps (I'm not an expert on the C# grammar or compiler architecture, so I wouldn't know) that the keyword serves an important (and perhaps critical) purpose for the compiler, but I disagree with the idea that the new keyword makes code easier to read or reason about.
Those languages were designed with that in mind, it wasn't bolted on later. Not that it matters at all what other languages do. Different languages have different syntax.
Dart wasn't designed with an optional new keyword from the start. It was added later, to make object trees easier to read and less cluttered. It was a very popular change.
@JeroMiya
They're both "functions which return an object",
No, one is a function that may return an object. The other is an allocation. It is an important distinction, behaviorally. Constructors don't return objects.
You could argue perhaps (I'm not an expert on the C# grammar or compiler architecture, so I wouldn't know) that the keyword serves an important (and perhaps critical) purpose for the compiler,
No, I argue that the keyword serves an important purpose for the reader. But it does also serve to disambiguate for the compiler as well given you could have a method and a type where the constructor has the same signature and there's no other way for the compiler to know what you intended.
No, one is a function that may return an object. The other is an allocation. It is an important distinction, behaviorally. Constructors don't return objects.
To clarify, I am speaking specifically in the context of an expression or as part of a larger expression, where the distinction is mostly irrelevant. A new expression is an expression that evaluates to a value. A function call is also an expression that evaluates to a value. Both of which involve a function being called. We could get into the weeds about allocation, null guarantees, and object identity differences, but in my opinion those are more or less akin to implementation details.
But it does also serve to disambiguate for the compiler as well given you could have a method and a type where the constructor has the same signature and there's no other way for the compiler to know what you intended.
I would argue that allowing the existence of the new keyword to disambiguate between a function and a class of the same name was not a great outcome - I realize we can't change change that rule without breaking code, but it certainly isn't an argument against this feature.
And, one of the reasons I've proposed that the developer would need to opt-in using a new kind of using syntax or keyword, is specifically to address this issue. If the developer opts-in, the compiler is then free to enforce identifier ambiguity rules more consistently in this case without breaking any existing code.
It makes sense to enforce the same identifier/overload ambiguity rules as two functions named the same thing with the same arguments. For example a local function vs an imported static function with a static using statement, or two static functions from different static classes. If this happens, the programmer easily can use one of many methods to explicitly disambiguate their code: using an explicit namespace, using this.Foo()
, creating a using alias (e.g. using Foo1 = ...etc...
) and so on.
@JeroMiya
And, one of the reasons I've proposed that the developer would need to opt-in using a new kind of using syntax or keyword, is specifically to address this issue.
This would create a separate dialect of the language within the language. All because you're prefer to not see new
. It doesn't make sense to expend all of this effort to solve no problems.
In languages like F# and Dart the keyword new
is optional while calling constructors.
In Rust or Kotlin (languages loved by programmers according to SO), there is no new
keyword.
In C++, new
means allocation and omitting new means object is on stack. But in C# new
may not allocate for value types.
I don't think making this change for saving a few keystrokes and making the code compact is feasible, because of C# language tradition. But other than that, I really don't see the new
is adding any clarity to the code.
I had my own proposal involving avoiding new
among other things- #1614
Despite word 'new' is quite short, it's still A WORD. Means "something which takes my attention to read, recognize and... discover it's just creation of object". It's annoying - THAT'S WHY "c-like syntax" won over pascal or basic languages. We already have too much (key)words in a program to waste time on simplistic things. What about some 'new-symbol'? Say, '$'. Then you write:
var a = $Point(1,2);// like new Point
Line b = $(a, $(1, 4));// constructor Line(Point, Point) - we omit any types we already know
Note on last line how less chars we have to type and how clearer now it looks.
@WrongBit, you wrote:
Despite word 'new' is quite short, it's still A WORD. Means "something which takes my attention to read, recognize and... discover it's just creation of object".
Replacing new with $
would still result in "something that takes your attention to read, recognize and ... discover it's just creation of object". Punctuation isn't magically shorter and easier to read/comprehend than a short word.
It's worth doing a bit of research into the way that reading actually works at a physiological and cognitive level.
As a readers eye saccades across a line of text, the eye picks up quite a wide swath of text. For native English speakers, folks with very high reading speeds (say, 800-1200 wpm) will actually only glance at two or three points on each line of text. Those with more common reading speeds (say, 400-800 wpm) are likely to primarily look at longer words of text, relying on peripheral vision to pick up on shorter words. Looking individually at every word or symbol in turn is a regrettably common habit that limits people to reading in the 100-250 wpm range.
The research I've read indicates that the effective difference in reading speed (including comprehension) of a sigil (say, "$") verses a short word ("new") is effectively zero.
Worse, introducing a $
as a synonym for new (because, of course, removing new would be a breaking change) would slow down comprehension because each developer would need to learn, recognize, and understand that "it's just like new, but shorter and more difficult to type".
Eliminating the new keyword requirement everywhere is a non-starter, as it potentially breaks existing code.
Introducing a new sigil to optionally replace new is also a non-starter, for reasons @theunrepentantgeek states - it's not an improvement in practice and more than likely worse.
The version of this proposal that has potential, in my view, would be something akin to a using static
directive, but for constructors. Like the using static statement, such a directive lets the user opt-in. Hopefully you could select a namespace or wildcard so you don't have to put twenty of these using statements at the top of the file.
One of the primary users of this feature would be people using MVU/Redux patterns and frameworks - i.e. immutable types and declarative data structures in C#. What I have to do today to work around this is to build up a library of public static functions which are just wrappers around constructors - then, I can use a using static directive to eliminate the cruft. But it's a lot of extra effort and maintenance:
// Static Utility library:
using ThirdParty.UIFramework;
namespace UI.Utils {
public static class UIConstructorWrappers {
public static Button Button(
String text = null,
Action click = null) => new Button(text, click);
// etc...
// since I'm not the "owner" of the UI framework in this example,
// I have to build up my own library to wrap every type in the UI framework.
}
}
// My View Code:
using static UI.Strings;
using static UI.Utils.UIConstructorWrappers;
// What I'd like to do:
// Eliminate most of the library code above (unless the utility actually
// does something useful besides wrap a constructor), and replace with this:
// using new ThirdParty.UIFramework;
public static class MainPage {
public static View Render(MainPageState state, Dispatch dispatch) =>
StackLayout(
Button(text: Button1Label, click: dispatch.Action1),
Button(text: Button2Label, click: dispatch.Action2),
StackLayout(
orientation: Horizontal,
children: ViewList(
Entry(
placeholder: EntryPlaceholder,
text: state.EntryValue,
textChanged: dispatch.TextChangedAction
)
)
) // etc...
);
// etc...
}
look at flutter code, Drop new keyword, It's awesome and much more clear:
class MyApp extends StatelessWidget {
Widget build(BuildContext context) {
final wordPair = new WordPair.random();
return MaterialApp(
title: 'Welcome to Flutter',
home: Scaffold(
appBar: AppBar(title: Text('Welcome to Flutter')),
body: Center(child: Text(wordPair.asPascalCase)),
),
);
}
}
@surfsky No it's seriously not clear that Scaffold
is class or function
In Kotlin, method names start with lowerCases, Class names with UpperCases. That's how methods and constructors are differentiated. May be it is same in Dart. In C#, methods and other class members starts with UpperCase. So, it may seem confusing.
It's not a big problem:
Drop-new-keyword is useful when creating a big-json-like object.
@surfsky No, it is a problem
With your reasoning, we need to read and understand that token before we know that it is the object and it actually create new object, or it is a function and it just return value. With the current approach we don't need to know at the first glance even what the word is, if it has parentheses without new, then it is function, if it is new XXXXX(
then it is a constructor. Even if I blur my vision I still see the new
separated from XXXXX
even without parentheses, it is constructor here and we are create new object
If there is anything that was json-like
, I would really be skeptic that it should be created from JSON. It should always be created from json and always have single entrypoint, which is parsed from json data or string, Upholding the MVC or MVVM
@Thaina I like to think of constructors as a kind of subset of functions which always return a new value, where other functions may return a cached value or no value at all. Technically they are semantically different but in practice I wouldn't say the distinction is very useful. Even if it were, syntax highlighting in an editor would help distinguish the two.
That being said, allowing constructors to be called using regular function syntax is a breaking change that requires per-file opt-in.
@JeroMiya
I like to think of constructors as a kind of subset of functions
I kind of understand and think so. But then again, having new
keyword is the key, it change perspective that from this point on it will allocate memory, not just call that function
Actually I familiar with this kind of concept from javascript, in that universe the class itself is function and derivation came from prototyping. So any function could be used to be new
ing
But that's the point. new
keyword is important. It was used to distinguished between calling normal function and creating new instance of object. So omitting it only lead to confusion
@Thaina The developers requesting this feature do so because it streamlines a common set of use cases - mostly declarative code with large object trees. Mostly these object trees are immutable or at least the tree itself is immutable if not each node. Probably the most common will be code-based UI views in an MVU or Redux pattern. Also common will be code-over-config frameworks, such as those to setup build systems, cloud configuration scripting, machine learning data transformation pipelines, and other similar applications.
I would argue that most of these primary use cases are ones in which it is not a high priority for the developer to know whether a given expression in the tree will result in a new value being allocated on the heap or not. Thus, although you are correct in pointing out that calling constructors using function call syntax obscures the fact that a new value is being allocated on the heap when the expression is executed, I would argue that for the most common use cases, that information is not relevant. At the end the of the expression evaluation, the result is the same: an object tree.
Further, given that this feature MUST be opt-in (I would suggest on a per-file level, enabled with a new using
syntax), a developer must choose to enable this streamlined new
syntax on a per-file and per-namespace level. I think you can safely say the developer is not confused about the choices they make themselves.
Couldn't you just define methods taht then return the new (or cached) value you want? i.e.:
Scaffold Scaffold(...)
=> new Scaffold(...);
Now you can just call Scaffold(...)
in your code without new
.
I would be far more interested in something that supports in line XML or in line Json. That's probably the future I miss the most from VB.
Maybe our own object literal syntax would be more appropriate. But just dropping the new
keyword seems like a halfhearted effort that won't satisfy anyone.
Couldn't you just define methods taht then return the new (or cached) value you want?
Yes that is the current workaround. Internally, I have a C# code generator and command line tool that takes an assembly and some filtering options and generates a static class with constructor wrappers over every type in the assembly that matches the filtering options. It has all the drawbacks you'd expect from a code-gen tool, however (e.g. maintenance costs, forward compatibility, code bloat, etc...). And I'd argue the need for a code generator to overcome something in the language is maybe a good sign that some streamlined syntax is needed in the language.
And I'd argue the need for a code generator to overcome something in the language is maybe a good sign that some streamlined syntax is needed in the language.
I honestly disagree, and often feel the opposite. If the problem can easily be solved by a generator, why bloat the language? Indeed, that's the direction we're pushing further toward with SourceGenerators.
I honestly disagree, and often feel the opposite. If the problem can easily be solved by a generator, why bloat the language? Indeed, that's the direction we're pushing further toward with SourceGenerators.
Many language proposals are intended to be quality of life improvements and have workarounds. The existance of a workaround isn't disqualifying, and having to write a source code generator is a pretty extreme workaround, to be honest. I think most people wouldn't bother.
I think most people wouldn't bother.
Agreed. I don't expect most people to do this. I expect some people to do this and then provide libraries that "most people" can then reference to get these capabilities.
Agreed. I don't expect most people to do this. I expect some people to do this and then provide libraries that "most people" can then reference to get these capabilities.
As I said, this is not a great workaround for several reasons beyond how easily the code generation integrates into the build system (or the compiler in the case of C# source generators). Using this workaround requires careful management of using statements to avoid name collision with the wrapped types (I use an "N" prefix in the generated static methods, but it's ugly). Additionally, if the runtime JIT or AOT is unable to inline these wrappers, they result in additional function call overhead over plain new expressions. They are also code bloat, which is important on mobile and other constrained platforms. They also introduce a large number of new symbols in the assembly metadata. Depending on the size of the target assembly this can cause a slowdown in the C# editor and the build.
Additionally, one important limitation of using a static method generator, particularly relevant in C# 9, is that you are unable to use an initializer. So, for example this workaround does not work for most collections, and in C# 9, init-only properties cannot be initialized. If there is a property which is not initialized by a constructor, then properly initializing an object is impossible without a helper method.
Using this workaround requires careful management of using statements to avoid name collision with the wrapped types
I don't know what that means. Why would there be name collisions here, but not have name collisions if we implicitly allow you to drop the new
?
Additionally, if the runtime JIT or AOT is unable to inline these wrappers
Why would tehy be unable to inline the wrapper? It would literally just be a forwarding function.
They are also code bloat, which is important on mobile and other constrained platforms.
I don't see why tooling cannot address that.
They also introduce a large number of new symbols in the assembly metadata. Depending on the size of the target assembly this can cause a slowdown in the C# editor
This should not cause a slowdown in the C# editor. We test out perf to hundreds of thousands of symbols without issue.
Additionally, one important limitation of using a static method generator, particularly relevant in C# 9, is that you are unable to use an initializer.
Why not? We're designing an entire feature around that concept. And it's more broadly applicable than just dropping 'new'. :)
I don't know what that means. Why would there be name collisions here, but not have name collisions if we implicitly allow you to drop the new?
If you generate wrappers for constructors, you're introducing a new static method per constructor. With a new syntax, you would not need to generate a wrapper, so no additional symbols are generated.
Why would tehy be unable to inline the wrapper? It would literally just be a forwarding function.
There are a number of reasons a JIT or AOT engine would choose not to inline a function regardless of its size including various thresholds.
I don't see why tooling cannot address that.
I don't see why a simple opt-in syntax improvement (already adopted by multiple languages outside of C#) that would eliminate the need for third party code generators, additional code shaking, more aggressive inlining, and which works well with object initializers, is not preferable to the status quo. Aside, perhaps, from a general resistance to any and all language proposals regardless of merit? I'm not saying it's as high priority as data classes and init-only properties in C# 9, but it certainly would be a welcome improvement in the same vein as the pattern matching improvements in C# 9 is all I'm saying.
Why not? We're designing an entire feature around that concept. And it's more broadly applicable than just dropping 'new'. :)
You cannot use the C# object initializer syntax on values returned from a method call and I'm not aware of any language proposals that allow this. Further, I would not support such a feature for init-only properties as it would make init-only properties mutable at call-stack boundaries.
There are a number of reasons a JIT or AOT engine would choose not to inline a function regardless of its size including various thresholds.
A static method that does nothing but call another function or constructor is right at the top of the list of functions that can be inlined.
I don't see why a simple opt-in syntax improvement
Making anything "opt-in" creates language dialects, and anything that creates a dialect needs to be a massive improvement to the language.
You cannot use the C# object initializer syntax on values returned from a method call and I'm not aware of any language proposals that allow this.
https://github.com/dotnet/csharplang/blob/master/meetings/2020/LDM-2020-04-20.md
You cannot use the C# object initializer syntax on values returned from a method call and I'm not aware of any language proposals that allow this.
I don't see why a simple opt-in syntax improvement (already adopted by multiple languages outside of C#)
Other languages have a different threshold for the introduction of different, subtly incompatible, dialects. The C++ world, for example, seems to positively thrive on the idea that the syntax and behaviour of the language can change markedly depending on compiler flags. #halfjoking
Python 3 was introduced as a breaking change in 2008 and so far it has taken that ecosystem 12 extremely painful years to migrate. Even though we have now seen the the last release of Python 2, the pain isn't over.
The C# team has an extremely high threshold for introduction of language dialects - they have to provide extremely high amounts of value. I think that nullable reference types is the first, and quite possibly will be the last, given that NRT seeks to tackle the so called billion dollar problem.
Remember as well that each additional flag doubles the number of dialects of the language - with just a dozen flags for "simple" features like this, you end up with over four thousand dialects of C#.
Aside, perhaps, from a general resistance to any and all language proposals regardless of merit?
I don't think this is the case. The folks who hang out and response to proposals in this repo are doing so because they're passionately interested in advancing the C# language. They tend to be smart, articulate, passionate - and they seldom all agree.
For any proposal to progress, it has to have significant value - every proposal starts at -100 points.
As you'll see if you review the (long!) discussion above, there are major issues with removing the new keyword.
It cannot be simply dropped as that will break existing code. See example.
Replacing the (already short) keyword with something else doesn't actually improve anything. See comment (mine).
Introducing a language dialect requires the feature to provide extraordinarily high value (essentially, starting at -100,000 points)
If you have a different solution to the problem, please suggest it. If your idea is good enough to be championed by one of the LDM, then it might even happen.
I could see some variation of the functor proposal supporting this request (#95). Trying to use the type name as a function would result in a call to a static Invoke
method, which could wrap the call to an actual constructor:
public class Foo {
public Foo(string value) { }
public static Foo Invoke(string value) => new Foo(value);
}
// you write:
var foo = Foo("Value");
// compiler translates into
var foo = Foo.Invoke("Value");
This is exactly how Scala works:
val some = Some("Value")
// is actually
val some = Some.apply("Value")
@theunrepentantgeek I understand the drawbacks, and I'm fully aware that this proposal is a long shot for the reasons you list. I'm just giving my feedback as someone who is not a compiler or language design expert - just someone who uses and loves C# day to day. Wearing that hat, I just wanted to express that this feature proposal would be a welcome improvement in terms of ergonomics and code readability for the kind of code I often write. I think it deserves "points" for that, at least.
Having experience with this particular feature in other languages, I can say that I really miss not having this in C#. I think it's important and useful enough to consider as a quality of life improvement, especially as declarative expression trees are becoming more mainstream in the dotnet community (e.g. MAUI MVU, Fabulous).
I see it as a feature that improves the overall ergonomics and readability of large C# expression trees, such as MVU or other code-based view functions. The new
keyword in this context is unnecessary noise in an already noisy syntactic environment of C# expression trees. In general, I see C# as suffering in the general area of noise and readability in this kind of code that often encourages C# developers to seek other languages that don't suffer as much from these drawbacks (like F#, Dart). That's why I support feature proposals like this that make the language better for this use case.
Also, would it be considered less of a "dialect" if object initializers were dropped from the proposal? As in, the new using
directive would be the semantic equivalent of generating static methods for each constructor with the same name as the class, but otherwise using all the same syntax. That wouldn't be quite as useful as the original proposal but would still be an improvement.
So for example, this code already works in today's C#, and it does not result in an ambiguous reference error because static methods and type names have different lookup rules:
// Foo.cs
namespace Foo
{
public class FooClass { }
public class FooClass2 { public FooClass2(int arg) {} }
// plus maybe 20-30 other classes in this namespace
public static class FooClassStatic {
public static FooClass FooClass() => new FooClass();
public static FooClass FooClass2(int arg) => new FooClass2(arg);
// plus maybe 20-30 other static methods in this static class
}
}
// Program.cs
using Foo;
using static Foo.FooClassStatic;
var fooList = new List<FooClass> {
FooClass(),
FooClass(),
FooClass2(12)
};
The new using statement would be equivalent to the above, but skips the need to write or generate that static method:
namespace Foo
{
public class FooClass { }
public class FooClass2 { public FooClass2(int arg) {} }
// plus maybe 20-30 other classes in this namespace
}
namespace Foo2
{
public class Foo2Class {}
public class NotGenerated {}
}
using Foo;
// "generate" static methods for all public types in Foo with public constructors
using static new Foo;
// only "generate" a static method for a specific type
using static new Foo2.Foo2Class;
// later in a function body:
var fooList = new List<FooClass> { FooClass(), FooClass(), FooClass(), Foo2Class() };
// ERROR because we didn't import the entire Foo2 namespace, just Foo2Class.
// var x = NotGenerated();
That seems like less of a dialect of C# and more like a compiler directive to "generate" static methods of an anonymous static class that is only in scope for that .cs file (even if in reality the compiler ends up just calling the constructor directly instead of invoking an actual generated static method, unless the generated method is used as a delegate/action/etc..).
I think that omitting the new
in Python was great choice, but because it's dynamically typed. You can pass a function or a class (aka functor) to a function which will call them, which would not be possible with new
. But C# is statically typed and I am not seeing any benefits. As stated above, it's just less clear, especially because as opposed to Python, for example, there is a difference between classes and functions.
But C# is statically typed and I am not seeing any benefits. As stated above, it's just less clear, especially because as opposed to Python, for example, there is a difference between classes and functions.
Dart is statically typed, yet you can remove the new key word. Just saying 🤷🏽♂️
But C# is statically typed and I am not seeing any benefits. As stated above, it's just less clear, especially because as opposed to Python, for example, there is a difference between classes and functions.
Dart is statically typed, yet you can remove the new key word. Just saying 🤷🏽♂️
Well, I don't agree with this design choice. And anyway C# made its decision since 2001, I think changing it (or even adding an option) will be confusing for no reason.
@surfsky No it's seriously not clear that
Scaffold
is class or function
Not sure how that makes any difference in the result or inference of intent?
There are lot situations where
new
keyword can be omitted.var p = new Point();
can be
var p = Point();
Keyword
new
will be required to resolve ambiguity, for example if Point() function and Point class are defined and for other such cases. Benefit is saved space, particularly with calling function and passing many new objects as arguments.