I disagree on this point. If there is a language feature that has been superseded by a better alternative, continuing to add sugar to the old feature only serves to perpetuate its use.
It embiggens the language while providing relatively little value in return. Furthermore, it adds confusion as to what should be considered idiomatic.
Tuples and deconstruction are so clearly better than out variables, I would have thought it would make more sense to deprecate the "out" feature entirely. Or, at the very least, not make it easier to use them.
Awkward and outdated features should be painful to use.
I also felt that this was a very odd addition. Even odder, the article doesn't even list tuples and deconstruction first.
With tuples especially, it's even worse, because the method name gets squished between two very similarly looking ()s, which is very different from how methods have historically looked in code. If I were scanning code fast, I'm not sure I would even read it as a function declaration.
C++ adopted its "auto ... -> ..." syntax a while ago - granted, they had a forcing function in form of decltype(), but many people also use it for readability reasons with complex return types. I hope C# follows suit; or, better yet, comes up with a unified type-after-name syntax a la ES6, that can be used everywhere in the language, while retaining existing syntax for back-compat purposes.
public TResult SomeMethod() where TResult : (string name, int id)
public SomeMethod(bool b) -> (string name, int id) { ... }
However, this may be undesirable due to confusion with => for lambdas and expression-bodied methods, especially in: public SomeMethod(bool b) -> (string name, int id) => ...
: is the next obvious candidate, and would unify the syntax with TypeScript and many other languages. But given that it's already used for labels and named arguments, I'm not sure there's enough room there to reuse it also for types.:: is another decent choice in terms of familiarity coming from other languages (Fortran, Haskell etc). But, unfortunately, it's already taken for extern alias, and I don't think this could be easily disambiguated in many contexts.
Now, if this is narrowly scoped to method return type only (i.e. we're not trying to invent a syntax that could later be used in a similar way to swap the type and the name in other places, like arguments and variables), and only as a fallback for when the usual "Type Name" arrangement has poor readability, perhaps take a hint from Ada and reuse "return"?
public SomeMethod(bool b) return (string name, int id) { ... }
A tad verbose, but if it's intended to be used sparingly, primarily with tuple-returning methods and deeply nested generics, I think that's okay - tuples themselves are pretty verbose when components are named.Or maybe borrow "as" from VB? It looks like it could be extended to other kinds of declarations in the future in a straightforward manner, without conflicting with its existing use for casts:
// Just for method return types
public SomeMethod(bool b) as (string name, int id) { ... }
// For everything
public SomeMethod(b as bool) as (name as string, id as int) {
var x as float;
TryFoo(out var y as bool);
...
switch (obj) {
case foo as Foo:
...
}
} public SomeMethod(bool b) -> (string name, int id) { ... }
When was this added to c++? I think I need to brush up on my lower level skills. var x as int;
"var" makes it a declaration, so "x" is the identifier, and "as" has to be the type specifier. var x = y as int;
"=" clearly separates the identifier from the initializer, and the latter is an expression, so "as" is the cast operator.Similar reasoning applies to other places where the two can appear - function parameter list, return type, field and property declarations etc.
So far as I can tell, by the time we get to the point where "as" would be used to specify the type of the declared entity, we will already know that it's a declaration, and that the only other token that can follow in existing grammar is "=", "{", or "=>" (for variable and field initializers and default parameter values, property getters and setters, and lambdas and expression-bodied members, respectively), and none of these start an expression. In all other contexts, "as" would be an operator.
template<typename A1, typename A2>
auto foo(A1 a1, A2 a2) -> decltype(a1 + a2) {
return a1 + a2;
}I'm worried this could result in a loss of focus, you can't make everyone happy all the time. c# is a fantastic language to develop applications in (web or desktop) but it's never going to be the fastest language around or be a systems level language. For me some of the other features listed here (like immutable records) would be a much better fit for where c# excels already.
One of the reasons we are stuck with C and C++ is because other language vendors, including Microsoft, dropped the ball regarding performance of type safe languages.
Do you think C++ would have been kept around if Java and the CLR had been AOT compiled to native code with focus on compiler optimisations since day one?
I really appreciate the efforts of the .NET team in adopting the Midori lessons in the standard .NET stack.
Consider virtual generic methods, for example. If your set of types is not statically bound, you can't allocate the appropriate number of vtable slots in advance, because you don't know all the instantiations.
I was already using dlls with plugins in Windows 3.1 and C++.
For that matter, it doesn't allow any templates across ABI boundary, except when you manually instantiate them (extern template) - and then only for those explicit instantiations. So it is effectively impossible to have a generic C++ API using templates that is not statically linked.
Borland C++ for Windows 3.x had an initial implementation for templates as they started to be discussed at ANSI and also supported exporting classes across dlls, providing both producer and consumer were Borland C++.
Here is the link for the Borland C++ compiler documentation, I was actually using the Turbo C++ version for Windows 3.1.
https://archive.org/details/bitsavers_borlandborn3.1Programm...
The BIDS, Borland International Data Structures were the template based library that replaced the object based one and could be accessible as a DLL as well.
To export classes from DLL one would do something like
// On the DLL side
class _export MyClass {...}
// On the consumer side
class huge MyClass {...}
Described on page 336 of the manual.If you check the the templates documentation, the generated code code could be externalized, page 152, via the -Jgx.
I was only a BIDS user across DLLs, but I can easily imagine a combination of _export/huge and -Jgd/-Jgx being what was necessary to make it all work.
"it doesn't allow any templates across ABI boundary, except when you manually instantiate them (extern template)"
So you can export template instantiations, yes. But you cannot export the template itself. For fairly obvious reasons - to instantiate a template requires compiling C++ code after substituting the tempalte parameters, so to export it across ABI boundary would require including the entirety of the C++ language (or at least a substantial subset - I guess you could desugar a bunch of stuff like, say, lambdas before) in that ABI.
And virtual templates are a whole other kettle of fish, because every instantiation of a virtual template would require a new slot in the vtable - or else the generic would have to dispatched by a single method, and the caller would have to supply runtime type information. In practice, C++ just forbids virtual templates outright.
In C#, this all works just fine, because generics still exist on bytecode level, which is what gets exported - and at runtime, the JIT will instantiate the generic by compiling that bytecode to native code, separately for every instantiation (in practice they unify them for reference types, because pointers are always of the same size; but value types get distinct JIT-compiled versions each).
For virtual generics, I'm actually not entirely sure how this works, but I would assume that vtable slots are allocated in batches and filled with instantiations as needed - and when you run out of slots and need to reallocate the vtable (and potentially shift indices of other methods in it), you can just JIT-recompile the bytecode for any method that happens to use the class with affected vtable.
There are many pieces of code that you probably use every day that go to great lengths to squeeze as much power as possible. Why not help these folks help us? I'm glad there is more focus on performance because we all benefit. (Hoping to see more on the CLR side.)
Rust or D seem like the best bet here
What is missing is a company like Microsoft to push it down to mainstream developers, at all costs, like it happen to all luddites.
Try OCaml.
Use a tractor.
Note: it's not like you can just sprinkle 'ref' on the return type of your methods willy nilly. Like 'ref'/'out' parameters, it requires you to do very specific things to keep your code safe/legal. As such, it's unlikely to just be added by people because, by and large, most code won't be equipped to actually handle it properly.
The codebases that will want to use this are already ones that have done a lot of work that makes them amenable to ref. i.e. game engines where you have large arrays of structs that you want to operate on in an efficient manner and whatnot.
I like the way its implemented in Perl. Use 'use strict' by default, and guard the block where you really need something unusual by 'no strict something' - refs, vars, subs - so neither compiler nor people reading your code never being confused whether is it a mistake or author's intention.
#pragma warning disable ${list of warnings}
and #pragma warning restore ${list of warnings}
https://msdn.microsoft.com/en-us/library/441722ys.aspxAlthough frankly the list of warnings to disable and restore consists of warning numbers, not names, which is not super convenient.
> Out variables seem like a mis-feature, especially when they are adding a better alternative (Tuples) in the same release.
Out variables are really great when working with existing code that predates Tuples (for example, the entire BCL). We don't just introduce language features that will only work well for new code. We also want to make the experience of coding against existing APIs feel better.
> Ref returns and locals look like a source of constant headaches.
That 'headache' has to be weighed against the needs of some parties to write very fast code and to have as little overhead as possible. ref returns enables a much more pleasant coding experience that enables these sorts of speedups in these specialized scenarios.
> It's much harder to reason with code when the data can be modified by random others bits of code.
There is a simple solution to this of course, don't expose your data through ref returns :)
For many (likely most) developers, ref returns simply won't be something that ever hits their radar. Similar to stackallocs and other esoteric features, this is really a targeted improvement for people who really like working in .Net but are finding it hard to squeeze out essential perf in some core scenarios.
The .net runtime supports this features fantastically. We wanted to make it available to people who like the power and safety of C#, but occasionally need some low level hooks to get that extra perf boost as well.