Quotes of the day:
Live broadcast of design meetings: we could call it C#-SPAN
We've made it three hours without slippery slopes coming up!
Agenda
This is the first design meeting for the version of C# coming after C# 6. We shall colloquially refer to it as C# 7. The meeting focused on setting the stage for the design process and homing in on major themes and features.
See also Language features currently under consideration by the language design group.
We have had great success sharing design notes publicly on CodePlex for the last year of C# 6 design. The ability of the community to see and respond to our thinking in real time has been much appreciated.
This time we want to increase the openness further:
The C# 7 design team currently consists of
Anders, as the chief language architect, has ultimate say, should that ever become necessary. Mads, as the language PM for C#, pulls together the agenda, runs the meetings and takes the notes. (Oooh, the power!)
To begin with, we meet 4 hours a week as we decide on the overall focus areas. There will not be a separate Visual Basic design meeting during this initial period, as many of the overall decisions are likely to apply to both and need to happen in concert.
Anyone can put a feature idea up as an _issue_ on GitHub. We'll keep an eye on those, and use them as input to language design.
A way to gauge interest in a feature is to put it up on UserVoice, where there's a voting system. This is important, because the set of people who hang out in our GitHub repo are not necessarily representative of our developer base at large.
Design notes are point-in-time documents, so we will put them up as _issues_ on GitHub. For a period of time, folks can comment on them and the reactions will feed into subsequent meetings.
If the design team decides to move on with a feature idea, we'll nominate an _owner_ for it, typically among the design team members, who will drive the activities related to the design of that feature: gathering feedback, making progress between meetings, etc. Most importantly, the owner will be responsible for maintaining a _proposal_ document that describes the current state of that feature, cross-linking with the design notes where it was discussed.
Since the proposals will evolve over time, they should be documents in the repo, with history tracked. When the proposal is first put up, and if there are major revisions, we will probably put up an issue too, as a place to gather comments. There can also be pull requests to the proposals.
We'll play with this process and find a balance.
We are very interested in other ideas, such as publishing recordings (or even live streaming?) of the design meeting themselves, and inviting non-Microsoft luminaries, e.g., from major players in the industry, onto the design team itself. We are certainly open to have "guests" (physical or virtual) when someone has insights that we want to leverage.
However, these are things we can get to over time. We are not going to do them right out of the gate.
It's important to note that the C# design team is still in charge of the language. This is not a democratic process. We derive immense value from comments and UserVoice votes, but in the end the governance model for C# is benevolent dictatorship. We think design in a small close-knit group where membership is long-term is the right model for ensuring that C# remains tasteful, consistent, not too big and generally not "designed by committee".
If we don't agree within the design team, that is typically a sign that there are offline activities that can lead to more insight. Usually, at the end of the day, we don't need to vote or have the Language Allfather make a final call.
Ideally we should prototype every feature we discuss, so as to get a good feel fro the feature and allow the best possible feedback from the community. That may note be realistic, but once we have a good candidate feature, we should try to fly it.
The cost of the prototyping is an issue. This may be feature dependent: Sometimes you want a quick throwaway prototype, sometimes it's more the first version of an actual implementation.
Could be done by a member of the design team, the product team or the community.
It's usually up to Mads to decide what's ready to discuss. Generally, if a design team member wants something on the agenda, they get it. There's no guarantee that we end up following the plan in the meeting; the published notes will just show the agenda as a summary of what was _actually_ discussed.
If a feature is great, we'll want to add it whether it fits in a theme or not. However, it's useful to have a number of categories that we can rally around, and that can help select features that work well together.
We discussed a number of likely themes to investigate for C# 7.
Today’s programs are connected and trade in rich, structured data: it’s what’s on the wire, it’s what apps and services produce, manipulate and consume.
Traditional object-oriented modeling is good for many things, but in many ways it deals rather poorly with this setup: it bunches functionality strongly with the data (through encapsulation), and often relies heavily on mutation of that state. It is "behavior-centric" instead of "data-centric".
Functional programming languages are often better set up for this: data is immutable (representing _information_, not _state_), and is manipulated from the outside, using a freely growable and context-dependent set of functions, rather than a fixed set of built-in virtual methods. Let’s continue being inspired by functional languages, and in particular other languages – F#, Scala, Swift – that aim to mix functional and object-oriented concepts as smoothly as possible.
Here are some possible C# features that belong under this theme:
A number of these features focus on the interplay between "kinds of types" and the ways they are used. It is worth thinking of this as a matrix, that lets you think about language support for e.g. denoting the types (_type expressions_), creating values of them (_literals_) and consuming them with matching (_patterns_) :
| Type | Denote | Create | Match |
| --- | --- | --- | --- |
| General | T
| new T()
, new T { x = e }
| T x
, var x
, *
|
| Primitive | int
, double
, bool
| 5
, .234
, false
| 5
, .234
, false
|
| String | string
| "Hello"
| "Hello"
|
| Tuple | (T1, T2)
| (e1, e2)
| (P1, P2)
|
| Record | { T1 x1, T2 x2 }
| new { x1 = e1, x2 = e2 }
| { x1 is P1, x2 is P2 }
|
| Array | T[]
| new T[e]
, { e1, e2 }
| { P1, P2 }
, P1 :: P2
|
| List | ? | ? | ? |
| Dictionary | ? | ? | ? |
| ... | | | |
A lot of the matrix above is filled in with speculative syntax, just to give an idea of how it could be used.
We expect to give many of the features on the list above a lot of attention over the coming months: they have a lot of potential for synergy if they are designed together.
C# and .NET has a heritage where it sometimes plays a bit fast and loose with both performance and reliability.
While (unlike, say, Java) it has structs and reified generics, there are still places where it is hard to get good performance. A top issue, for instance is the frequent need to copy, rather than reference. When devices are small and cloud compute cycles come with a cost, performance certainly starts to matter more than it used to.
On the reliability side, while (unlike, say, C and C++) C# is generally memory safe, there are certainly places where it is hard to control or trust exactly what is going on (e.g., destruction/finalization).
Many of these issues tend to show up in particular on the boundary to unmanaged code - i.e. when doing interop. Having coarse-grained interop isn't always an option, so the less it costs and the less risky it is to cross the boundary, the better.
Internally at Microsoft there have been research projects to investigate options here. Some of the outcomes are now ripe to feed into the design of C# itself, while others can affect the .NET Framework, result in useful Roslyn analyzers, etc.
Over the coming months we will take several of these problems and ideas and see if we can find great ways of putting them in the hands of C# developers.
The once set-in-stone issue of how .NET programs are factored and combined is now under rapid evolution.
With generalized extension members as an exception, most work here may not fall in the language scope, but is more tooling-oriented:
This is a theme that shouldn't be driven primarily from the languages, but we should be open to support at the language level.
There may be interesting things we can do specifically to help with the distributed nature of modern computing.
Also, await in catch and finally probably didn't make it into VB 14. We should add those the next time around.
Metaprogramming has been around as a theme on the radar for a long time, and arguably Roslyn is a big metaprogramming project aimed at writing programs about programs. However, at the language level we continue not to have a particularly good handle on metaprogramming.
Extention methods and partial classes both feel like features that could grow into allowing _generated_ parts of source code to merge smoothly with _hand-written_ parts. But if generated parts are themselves the result of language syntax - e.g. attributes in source code, then things quickly get messy from a tooling perspective. A keystroke in file A may cause different code to be generated into file B by some custom program, which in turn may change the meaning of A. Not a feedback loop we're eager to have to handle in real time at 20 ms keystroke speed!
Oftentimes the eagerness to generate source comes from it being too hard to express your concept beautifully as a library or an abstraction. Increasing the power of abstraction mechanisms in the language itself, or just the syntax for applying them, might remove a lot of the motivation for generated boilerplate code.
Features that may reduce the need for boilerplate and codegen:
With null-conditional operators such as x?.y
C# 6 starts down a path of more null-tolerant operations. You could certainly imagine taking that further to allow e.g. awaiting or foreach'ing null, etc.
On top of that, there's a long-standing request for non-nullable reference types, where the type system helps you ensure that a value can't be null, and therefore is safe to access.
Importantly such a feature might go along well with proper safe _nullable_ reference types, where you simply cannot access the members until you've checked for null. This would go great with pattern matching!
Of course that'd be a lot of new expressiveness, and we'd have to reconcile a lot of things to keep it compatible. In his blog, Eric Lippert mentions a number of reasons why non-nullable reference types would be next to impossible to fully guarantee. To be fully supported, they would also have to be known to the runtime; they couldn't just be handled by the compiler.
Of course we could try to settle for a less ambitious approach. Finding the right balance here is crucial.
_Type providers_: This is a whole different kind of language feature, currently known only from F#. We wouldn't be able to just grab F#'s model though; there'd be a whole lot of design work to get this one right!
_Better better betterness_: In C# we made some simplifications and generalizations to overload resolution, affectionately known as "better betterness". We could think of more ways to improve overload resolution; e.g. tie breaking on staticness or whether constraints match, instead of giving compiler errors when other candidates would work.
_Scripting_: The scripting dialect of C# includes features not currently allowed in C# "proper": statements and member declarations at the top level. We could consider adopting some of them.
_params IEnumerable_.
_Binary literals and digit separators_.
The Matrix above represents a feature set that's strongly connected, and should probably be talked about together: we can add kinds of types (e.g. tuples, records), we can add syntax for representing those types or creating instances of them, and we can add ways to match them as part of a greater pattern matching scheme.
Core then is to have a pattern matching framework in the language: A way of asking if a piece of data has a particular shape, and if so, extracting pieces of it.
``` c#
if (o is Point(var x, 5)) ...
There are probably at least two ways you want to use "patterns":
1. As part of an expression, where the result is a bool signaling whether the pattern matched a given value, and where variables in the pattern are in scope throughout the statement in which the pattern occurs.
2. As a case in a switch statement, where the case is picked if the pattern matches, and the variables in the pattern are in scope throughout the statements of that case.
A strong candidate syntax for the expression syntax is a generalization of the `is` expression: we consider the type in an `is` expression just a special case, and start allowing any pattern on the right hand side. Thus, the following would be valid `is` expressions:
``` c#
if (o is Point(*, 5) p) Console.WriteLine(o.x);
if (o is Point p) Console.WriteLine(p.x);
if (p is (var x, 5) ...
Variable declarations in an expression would have the same scope questions as declaration expressions did.
A strong candidate for the switch syntax is to simply generalize current switch statements so that
``` c#
switch (o) {
case string s:
Console.WriteLine(s);
break;
case int i:
Console.WriteLine($"Number {i}");
break;
case Point(int x, int y):
Console.WriteLine("({x},{y})");
break;
case null:
Console.WriteLine("
break
}
Other syntaxes you can think of:
_Expression-based switch_: An expression form where you can have multiple cases, each producing a result value of the same type.
_Unconditional deconstruction_: It might be useful to separate the deconstruction functionality out from the checking, and be able to unconditionally extract parts from a value that you know the type of:
``` c#
(var x, var y) = getPoint();
There is a potential issue here where the value could be null, and there's no check for it. It's probably ok to have a null reference exception in this case.
It would be a design goal to have symmetry between construction and deconstruction syntaxes.
Patterns _at least_ have type testing, value comparison and deconstruction aspects to them.
There may be ways for a type to specify its deconstruction syntax.
In addition it is worth considering something along the lines of "active patterns", where a type can specify logic to determine whether a pattern applies to it or not.
Imagine positional deconstruction or active patterns could be expressed with certain methods:
``` c#
class Point {
public Point(int x, int y) {...}
void Deconstruct(out int x, out int y) { ... }
static bool Match(Point p, out int x, out int y) ...
static bool Match(JObject json, out int x, out int y) ...
}
We could imagine separate syntax for specifying this.
One pattern that does not put new requirements on the type is matching against properties/fields:
``` c#
if (o is Point { X is var x, Y is 0 }) ...
Open question: are the variables from patterns mutable?
This has a strong similarity to declaration expressions, and they could coexist, with shared scope rules.
Let's not go deep on records now, but we are aware that we need to reconcile them with primary constructors, as well as with pattern matching.
One feature that could lead to a lot of efficiency would be the ability to have "windows" into arrays - or even onto unmanaged swaths of memory passed along through interop. The amount of copying that could be avoided in some scenarios is probably very significant.
Array slices represent an interesting design dilemma between performance and usability. There is nothing about an array slice that is functionally different from an array: You can get its length and access its elements. For all intents and purposes they are indistinguishable. So the best user experience would certainly be that slices just _are_ arrays - that they share the same type. That way, all the existing code that operates on arrays can work on slices too, without modification.
Of course this would require quite a change to the runtime. The performance consequences of that could be negative even on the existing kind of arrays. As importantly, slices themselves would be more efficiently represented by a struct type, and for high-perf scenarios, having to allocate a heap object for them might be prohibitive.
One intermediate approach might be to have slices be a struct type Slice
Just like the language today has ref parameters, we could allow locals and even return values to be by ref
. This would be particularly useful for interop scenarios, but could in general help avoid copying. Essentially you could return a "safe pointer" e.g. to a slot in an array.
The runtime already fully allows this, so it would just be a matter of surfacing it in the language syntax. It may come with a significant conceptual burden, however. If a method call can return a _variable_ as opposed to a _value_, does that mean you can now assign to it?:
``` c#
m(x, y) = 5;
You can now imagine getter-only properties or indexers returning refs that can be assigned to. Would this be quite confusing?
There would probably need to be some pretty restrictive guidelines about how and why this is used.
## readonly parameters and locals
Parameters and locals can be captured by lambdas and thereby accessed concurrently, but there's no way to protect them from shared-mutual-state issues: they can't be readonly.
In general, most parameters and many locals are never intended to be assigned to after they get their initial value. Allowing `readonly` on them would express that intent clearly.
One problem is that this feature might be an "attractive nuisance". Whereas the "right thing" to do would nearly always be to make parameters and locals readonly, it would clutter the code significantly to do so.
An idea to partly alleviate this is to allow the combination `readonly var` on a local variable to be contracted to `val` or something short like that. More generally we could try to simply think of a shorter keyword than the established `readonly` to express the readonly-ness.
## Lambda capture lists
Lambda expressions can refer to enclosing variables:
``` c#
var name = GetName();
var query = customers.Where(c => c.Name == name);
This has a number of consequences, all transparent to the developer:
For these reasons, the recently introduced lambdas in C++ offer the possibility for a lambda to explicitly specify what can be captured (and how). We could consider a similar feature, e.g.:
``` c#
var name = GetName();
var query = customers.Where([name]c => c.Name == name);
This ensures that the lambda only captures `name` and no other variable. In a way the most useful annotation would be the empty `[]`, making sure that the lambda is never accidentally modified to capture _anything_.
One problem is that it frankly looks horrible. There are probably other syntaxes we could consider. Indeed we need to think about the possibility that we would ever add nested functions or class declarations: whatever capture specification syntax we come up with would have to also work for them.
C# always captures "by reference": the lambda can observe and effect changes to the original variable. An option with capture lists would be to allow other modes of capture, notable "by value", where the variable is copied rather than lifted:
``` c#
var name = GetName();
var query = customers.Where([val name]c => c.Name == name);
This might not be _too_ useful, as it has the same effect as introducing another local initialized to the value of the original one, and then capture _that_ instead.
If we don't want capture list as a full-blown feature, we could consider allowing attributes on lambdas and then having a Roslyn analyzer check that the capture is as specified.
.NET already has a contract system, that allows annotation of methods with pre- and post-conditions. It grew out of the Spec# research project, and requires post-compile IL rewriting to take full effect. Because it has no language syntax, specifying the contracts can get pretty ugly.
It has often been proposed that we should add specific contract syntax:
``` c#
public void Remove(string item)
requires item != null
ensures Count >= 0
{
...
}
```
One radical idea is for these contracts to be purely runtime enforced: they would simply turn into checks throwing exceptions (or FailFast'ing - an approach that would need further discussion, but seems very attractive).
When you think about how much code is currently occupied with arguments and result checking, this certainly seems like an attractive way to reduce code bloat and improve readability.
Furthermore, the contracts can produce metadata that can be picked up and displayed by tools.
You could imagine dedicated syntax for common cases - notably null checks. Maybe that is the way we get some non-nullability into the system?
So, array slices are basically an improved version of ArraySegment<T>
?
While Pattern matching is awesome, I'm still disappointed to know that break;
is mandatory. I'm pretty sure you've had lots of discussions in codeplex or elsewhere (which I've never read) so no need for rationale or history behind this, but that's about the only part of C# which I have to feel is _lamely_ designed.
@svick: Yeah I guess. With possible language support.
@shunsukeaida: this is totally a straw man syntax - we aren't even close to settling on a specific syntax. However, if we want to fit pattern matching into switch, we have to kind of blend in well. One might argue that we could just get rid of break, and make it implicit and the end of a case block. That's certainly worth considering.
@MadsTorgersen Something not mentioned in relation to pattern matching: have discriminated unions been considered?
@MadsTorgersen @shunsukeaida I proposed a better switch syntax
on CodePlex (independently from destructuring) https://roslyn.codeplex.com/discussions/565550, though it might not work with labels.
I think a better switch
syntax is rather important whether pattern matching gets into the language or not.
Anyone can put a feature idea up as an issue on GitHub. We'll keep an eye on those, and use them as input to language design.
Is there some way to distinguish those from e.g. Roslyn bugs? E.g. some title prefix or so? Labels are good but I can't assign them when reporting the issue I believe.
And I think it would be cool to have some minimal format for it, e.g. at least require the description of the problem, a proposed solution, some use cases using the proposed solution. BCL team seems to be doing a good job there with speclets.
Also I think some certain yes/no on proposals would be great, so that any GitHub proposal is not only considered, but either rejected, accepted for prototyping, or sent to rework due to some design constraints. Again I think BCL team is doing great with their periodic review approach.
Here's a theme suggestion.
With multi-core becoming commonplace and the nice Task and TPL apis, I see more and more concurrent programming, even if just a few (2-3) background threads.
It would be very nice to get some help from C# regarding correctness here. Immutable data structures are a big help, but for mutable data the main issue is that nothing formally indicates which thread has data ownership, or if data is shared in a read-only fashion, or if data must be accessed inside a lock. In complex programs and large teams this stuff is really hard to get right.
C# was a rockstar when it introduced async
to help write asynchronous code. I know it's a very hard topic but I would love to see C# bring safe concurrent programming to mainstream.
I would love to see more native language support for metaprogramming. Mixins and/or traits would certainly help with code reuse challenges and I would personally love to see one of these make it in. While T4 templates work okay for code generation, they often feel clunky and hacky (for example, even though it's a tooling thing, the fact that VS addins are needed just to consistently evaluate them is a clue something is off). Some kind of language support or hook for code generation would be welcome. I would also love to see some sort of rudimentary support for aspects and weaving. PostSharp works well and has a nice API, but requires extra libraries and IL rewriting. Fody aspects work, but there's a really steep learning curve. I'm guessing full AOP support would be way out of scope for this language update, but incremental support or even hooks (perhaps in Roslyn) would be welcomed.
There was also mention of improved overload resolution. This has been a particular pain point of mine, especially when dealing with generics and extension methods. For example, it would be awesome if generic constraints were taken into account when determining a match. I understand the reason why they're not considered (I.e., not part of the method signature) but it would be great if there were a way to overcome this.
+1 AOP can have lots of useful applications, some of them have been requested by the community for a long time. A few examples:
INotifyPropertyChanged
implementation.@jods4 Of interest may be the fact that @jaredpar, one of the coauthors of the _Uniqueness and Reference Immutability for Safe Parallelism_ paper, is now on the Roslyn team and said:
a part of my job will be trying to integrate some of the goodness that came out of our research back into the language
I think let
might be a useful convention for readonly var
, or even const
, though that's probably leading too much down the path of too many meanings for const
that C/C++ fall prey to.
@MadsTorgersen What do you mean by delegation? Following theories of incomplete objects that get composed by delegation with proper late-binding semantics maybe?
Something not mentioned in relation to pattern matching: have discriminated unions been considered?
@agocke Yes, in the original proposal discriminated unions were implemented with record subclassing — similar to case classes in Scala.
@MadsTorgersen By the way, regarding the state of pattern matching. If you do decide to consider them for C# 7, will the first prototype be merged into the current Github source as a feature branch? Will the community be able to contribute to such prototypes? I think you've mentioned before that you want to simplify the PR process in a couple of months, so that external feature prototyping/bug fixing would be easier.
Non-nullable reference types might be better served with another approach. Assess the feasibility of CLR support for describing a non-null reference type. Even if C# cannot currently take advantage of non-nullable reference types there might be another .NET language that figures out how.
Not about new Visual Basic language version? Is Visual Basic coming to die or was placed in the background? I love VB and I'd love to hear about new features :smile: for it.
@HoracioFilho They mentioned that they are planning the features for both C# and VB right now.
To begin with, we meet 4 hours a week as we decide on the overall focus areas. There will not be a separate Visual Basic design meeting during this initial period, as many of the overall decisions are likely to apply to both and need to happen in concert.
One thing HPC like devs could benefit from, is have the ability to "construct" primitive array types off of memory mapped file, like java's nio supports...
I realize this is mainly a runtime feature, rather than a c# feature, is there a "better" place to discuss those?
Something that I missed before, and reactive extensions almost gave it to me:
Ability to combine await and yield, resulting in an asynchronous sequence.
async var GenerateNumbers()
{
int i = 0;
while (true)
{
await Task.Delay(TimeSpan.FromSeconds(1));
yield return i++;
}
}
foreach(await int item in GenerateNumbers())
{
WriteLine("Item: \{item}");
}
readonly var
could be abbreviated as let
, which is already a contextual keyword within query comprehension expressions and semantically declares a readonly
variable...
+1 to the Contracts system. There's already a similar concept with type constraints for generics.
class Foo<T> where T : IComparable { }
An extension to this pattern for functions would be intuitive to anyone familiar with constraints.
void Foo(string bar) where bar != null, Count > 0 { }
Would separate 'ensures' and 'requires' actually be necessary? Could the statement be inferred?
@agocke: We are trying to come up with a general framework for pattern matching over classes. Ideally there wouldn't be a new "thing" in the language called algebraic datatypes or discriminated unions. Instead there may be compact syntax for describing hierarchies of simple value types (that would happen to be well suited for pattern matching) as a shorthand for class declarations.
@ashmind: yeah, maybe it's time to revamp switch. Worth a think.
@ashmind: I think we'll go through and apply the labels. We'll build up our processes as we go - the BCL team are ahead of us here, and we'll draw on their experiences.
@jods4: safe concurrency is an insanely hard problem. Not sure what we'd do.
@somedave: realistically I can't see us doing something about metaprogramming at the language level before we have a very clear idea of a) what would really move the needle for a lot of developers, and b) how to deal with it at a tooling level.
@jods4: AOP is notoriously hard to reason about for a developer. It's a very big hammer.
@bojanrajkovic, @jonpryor: let
is certainly a candidate.
@biboudis: Full-blown delegation (with this-binding and everything) seems out of the question - that's a whole alternative mechanism to inheritance. But some languages have this nifty little implement-interface-by-redirection trick. Not sure if it's worthwhile or even sane.
@apskim: No clear decisions yet as to how we will share prototypes. For the time being, most of the team is heads down making the _upcoming_ version great. This further-out blue sky stuff won't get priority until that's out the door. Yes, would be great to involve the community in prototyping.
@Romoku: I'd love to get non-nullable reference types into the CLR. It seems a tall order even there: what's inside an array of non-nullable reference type when it's first created? etc.
@HoracioFilho: Yeah, @Romoku has it right. It doesn't make sense to start separate efforts. Let's get the broad brushstrokes worked out and then split out to language-lawyer on the syntax. :-)
@damageboy: If I understand you correctly, yes that would be an awesome interop feature: Array-typed "windows" onto native data. Privileged (and unsafe!) methods would create them, but be able to share them with your code.
@jvlppm: Yes! When I mentioned "async sequences" this is the kind of thing I had in mind.
@MrDoomBringer: Whatever the syntax, it would certainly occupy the same "region" of a method declaration as the constraints. Maybe it makes sense to merge them.
@apskim @MadsTorgersen
Technically, you're correct, but there are actually no new features there specific to discriminated unions. :) The method of generating discriminated unions in the draft specification has one (to me very significant) weakness -- it has no specification of completeness checking in switch statements right now. One way to add this would be to add specialized support just for discriminated unions, for example coming up with a new syntax for enum
which desugers to a discriminated union behind the scenes.
Alternatively, I would like a spec addition that guarantees that the following data structure provides completeness checking in a switch statement.
public abstract class BinaryTree<T>
{
private BinaryTree() {};
public sealed class Leaf<U>() : BinaryTree<U>;
public sealed class Node<U>(U item, U left, U right) : BinaryTree<U>;
}
It's a little more heavyweight than some _de novo_ syntax, but it works. Obviously I would be volunteering to implement this warning. ;)
@MadsTorgersen From what I understand of how Eric Lippert and Spec# describe non-null references types the contents of the array cannot be null when _observed_ during the program execution. This means that up to the point of observance the state can be undetermined, but there must be a value at the point of observance.
@somedave Agreed on the AOP.
PostSharp is amazing, but It can be hard to keep it working right on a large team of developers, and it's pretty expensive for all the bells and whistles for a large team as well, even if only a couple of people are even writing the code.
Some language level support for generic argument and result manipulation on methods (like OnMethodBoundaryAspect) alone would be a huge step to meeting the need for metaprogramming and supplanting the wonkiness of PostSharp.
@MadsTorgersen
The PostSharp VisualStudio add-on seems to allow one to easily see which methods are manipulated by which aspects, both at the "This Method is manipulated by This Aspect" and "This Aspect manipulates These Methods".
We've saved ourselves literally thousands of lines of code, but it gets pretty expensive and it's a pretty obscure technical expense that is hard to justify to management types.
It would also be nice if C#/.NET were the first language/framework with anything approaching the kind of reach it has to REALLY have built-in first-class AOP facilities in a language. AspectJ and the things found in some of the dynamic languages or the LISPs are not exactly getting a lot of attention these days. I'd personally see it as a huge huge win for this new open design process from a developer perspective.
@MadsTorgersen you understood me perfectly
How about Units of Measure (like F#)?
From the perspective of performance and convenience, I prefer to use primitive values (int ,byte, etc.), but at the same time, from the perspective of reliability, I'd like to use user-defined values. This dilemma can be solved by Units of Measure.
+1 for Contracts from me.
The current solution seems half hearted and not really supported very well.
Non-nullness could IMO be left to contracts, IF there is a static analyzer that can enforce this.
If they are to become a language feature, common cases could be expressed much shorter.
I'm thinking something like:
``` c#
public int >= 0 M(string! s, double < 100 y, MyClass c)
requires c.IsInitialized
{}
which would be the same as
``` c#
public int M(string s, double y)
requires s != null,
requires y < 100,
requires c..IsInitialized
ensures result >= 0
{}
However it could looks a bit messy. Thoughts?
PS: the example
``` c#
if (o is Point(*, 5) p) Console.WriteLine(o.x);
should that be
``` c#
if (o is Point(*, 5) p) Console.WriteLine(p.x);
or am I misunderstanding?
Sorry to leave a non constructive comment here but I do have a question related to this process of specifying and designing C#7.
I am interested in watching and studying this process and caught the note about this being broadcast live. What is the best way to follow along and maybe watch these meetings?
I am an undergraduate student who just started a class on language specifications and design and it's definitely one of the most interesting topics I have studied thus far. I don't really use c# but I am really interested in studying the process of language design and that seems to be (partly or mostly) independent of the exact language being specified. I also think it's important, for my benefit, to note here that C# is obviously not a new language and so there is a lot of base work being built upon here.
Anyway, with that said I would love to follow along as closely as I can and would like some more information about how to do that.
Thanks, -TuckerD
:+1: Method contracts! Yes please. Also really liked the idea of syntax for tuples and records. Pattern matching - even if just within switch case statements - would be fantastic as well.
If the 'pattern on the right hand side' allows matching on subclasses of the data on the left of this 'is' operator, then without having the capability of exhaustive checks, (as seems from what is described so far), imho the most important benefits of pattern matching are lost.
An 'exhaustive check' would mean that there would be a compiler warning if new subclasses were added to the data being matched on that didn't have cases for that new subclass in existing pattern matching code.
Actually, I'm thinking now it may be difficult to make exhaustive checks work for concrete classes because of ambiguity with the syntax allowing destructuring of the primary constructor.
Perhaps there could exhaustive checks only when matching on abstract classes if that causes less ambiguity.
Thinking about it some more, classes are not closed, so exhaustive checks would make no sense... This really is not what I would call pattern matching without discriminated unions. This should just be called "destructuring"
Thanks @MadsTorgersen - a few various thoughts:
Can we "mark" this integer (or Guid, or long, etc) of customerId (pulled from a database for example) as a "CustomerId" type?
public CustomerId : int { }
I want to prevent a method that takes:
public void Charge(int customerId)
... accidentally being passed in a billingId (also an INT).
Ideally my interface was:
public void Charge(CustomerId customerId)
... and passing in a billingId would result in a compilation error.
@plasma, regarding your "type safe basic type", what's wrong with:
``` c#
public struct CustomerId {
public int Id { get; }
public CustomerId(int id) { this.Id = id; }
// optional
public static implicit int(CustomerId cId) => cId.Id;
}
If you need many of those, you can just create an abstract base class:
``` c#
public abstract class IdBase {
public int Id { get; }
public IdBase (int id) { this.Id = id; }
// optional
public static implicit int(IdBase cId) => cId.Id;
}
public class CustomerId : Idbase {}
It's not a struct anymore, but it should hardly matter.
It's a bit of typing, but with Record types and primary constructors it'll get so short it's essentially nothing.
c#
public struct CustomerId(int id) {
public int Id { get; } = id;
}
I believe the real feature you want is ValueType (pseudo?) - inheritance, a form a compiler enforced type aliasing.
I don't think adding yet another form of "type" to the language is a good idea, it's getting kinda complicated as it is.
Apply the readonly
modifier to classes, methods, and parameters to help support immutable data structures. Perhaps add the mutable
keyword for readonly
classes the way C++ uses it.
I've wanted static methods in an interface before, but generic constructor constraints might have been the underlying problem.
Could you implement constraints at compile time using a static analyzer? Like using an unassigned variable is a compiler warning (error?) now.
Discriminated unions like Rust has.
Interfaces with default implementations like Java just added (is thinking about adding?). Is this different than traits or mixins in large way?
What if you make the lambda capture list an extended portion of the parameter list?
C#
var number = GetNumber();
var name = GetName();
var query = customers.Where((c, ref name, value number) => c.Name == name || c.Number == number);`
@ryancerium
:+1: for readonly class
with mutable
members.
What if you make the lambda capture list an extended portion of the parameter list?
csharp var number = GetNumber(); var name = GetName(); var query = customers.Where((c, ref name, value number) => c.Name == name || c.Number == number);```
I'd be against this if only because of the cognative load of differentiating between captures and params. While [number, value name](c) => ...
isn't the prettiest, it's at least a lot more immediately clear.
How about adding private variables inside a property, to prevent side effects from modifying the the backing field directly
public int Id
{
int _id = 0;
get { return _id; }
set { _id = value; }
}
The pattern matching construct should be an expression and not a statement like switch. My 2 cents.
@Fizzelen wouldn't that just be a good old fashion property at this point? Or are you referring to doing something like:
public int Id
{
int _id = 0;
get { return _id * 2; }
set { _id = value / 2; }
}
For Lambda Captures, perhaps something inline could be useful, such as:
var name = GetName();
var query = customers.Where(c => c.Name == [name]);
or
var name = GetName();
var query = customers.Where(c => c.Name == {name});
I would think something like this (perhaps not this exact syntax) could avoid the mess of having a capture list before the expression, and could allow it to capture sub properties from an object rather than the whole object as well, i.e
var person = GetPerson();
var query = customers.Where(c => c.Name == {person.Name});
So here, it would capture the value of person.name
and not the whole person object.
This could also work fine with other capture options, such as by value, {val name}
or {val person.Name}
if this feature were desired, not sure I personally see the benefit of that either as we can create a variable to capture instead.
This might still get tricky with nested functions or nested class declarations, but if the capture was { person.Name.ToString()}
- perhaps it would be aware and capture the property and call on it separately? or perhaps we would have to call it like so: {person.Name}.ToString()
- and then calling {person.Name.ToString()}
would actually capture the ToString()
call.
@tophallen
Something like this maybe?:
var name = GetName();
var query = customers.Where(c => c.Name == |val name|);
Though I'm not sure what syntax would actually be happy point.
@Fizzelen I suggest just having an auto-field called field
instead, e.g.
public int Id {
get { return field; }
set { field = value; }
}
I would welcome any sort of "const"ness on method parameters. More powerful switch statement that can handle expression non-compile time constants would also help a lot.
@tophallen, @RichiCoder1 IMO, the folks talking about lambda capture syntax seem to be missing the point by talking about in-lining this new syntax. We don't really get anything that way. The nice part about the way @MadsTorgersen originally typed it, is that it is "foward declared" before it is actually used, much like a method parameter or field or whatever, so to use it in the executing part of the lambda, you have to declare that you want to bring it into the closure before you actually use it.
All you do by inlining it into the operative part of the lambda is introduce some more complicated syntax that doesn't gain us anything. I'm not saying the original syntax is pretty, or should be used, but that is a very clear benefit of it.
As a less ambitious approach than non-nullable reference types, I think I'm okay with having a shorter approach to check that a variable neither refers to null
nor has a value generally considered as blank (e.g. string is empty or array length is zero). String.IsNullOrEmpty(foo)
is still a bit tiring even with stating using.
Maybe akin to ask if it's ever possible for null
to call a method though.
@jamesbascle true, but the compiler could look at the expression for pattern matching, and forward declare on build, and that would allow it to not capture the whole scope onto the heap, and you could pick sub properties, or call a method to capture a specific part of a class, or to capture a state, so while the syntax might get a bit cluttered (I see what you mean though, as this would especially be annoying when you use the same captured variable multiple times (i.e. c => c.StartDate <= [myDate] && c.EndDate >= [myDate]
), you could get the benefits of explicit capture. Forward declaring would make for less work however.
To your point perhaps the suggestion by @ryancerium could be tweaked to keep the readability and look something like this?
``` C#
var name = GetName();
var query = customers.Where(([name], c) => c.Name == name);
``` C#
var person = GetPerson();
var query = customers.Where(([person.Name],[val person.Id], c) =>
c.Name == person.Name && c.Id == person.Id);
//or if we wanted captures to be one thing
var query = customers.Where(([person.Name, val person.Id], c) =>
c.Name == person.Name && c.Id == person.Id);
In this way it keeps the expression cleaner, but also makes it clear that it is a captured value and not coming from the expression itself, but is to be captured in the heap for the expression to use. The issue that would be left with this method would be, should []
be required to ensure that you capture nothing? Or could it be specified some other way?
ObservableCollection.AddRange()
@tophallen I could be wrong, but I'm pretty sure that the compiler-generated lambda helper classes only bring "this" (whatever class it is in that context) and any referenced variables, so I think it already doesn't pull in the entire calling scope, just those it needs.
I'm glad you are thinking about virtual extension methods, it would be great to have dynamic binding outside of methods. For example something like
public string DoSomething(virtual ISomething s){
return "this is the base method";
}
public string DoSomething(SomethingImplementation s){
return "s is SomethingImplementation";
}
public string DoSomething(SomethingElse s){
return "s is SomethingElse";
}
//...
ISomething s;
s = new SomethingImplementation();
DoSomething(s)//returns "s is SomethingImplementation";
s = new SomethingElse();
DoSomething(s)//returns "s is SomethingElse";
This is possible to do with dynamic, but dynamic isn't restrictive enough, as it will match any type. With virtual it would be possible to match only on subclasses/implementations of a type. In the above case the method marked as virtual would be the fallback in the case that a new type is introduced which doesn't have an implementation of DoSomething
C# really need a stricter version of enum, one that cannot be cast from int so the compiler can do static analysis on it, for example in switch/case:
enum Maybe{Yep, Nope};
//...
public bool IsYep(Maybe maybe){
switch(maybe){
case Yep: return true;
case Nope: return false;
}
}
The above code will not compile, since the compiler is unable to tell that all possible paths through the IsYep method has a return value. The way to fix this is to add a default case, which is really not needed. A stricter implementation of enum would have the above case compiling without error but not compiling in the following case (because not all the enum cases have been tested in the switch/case):
enum Color{Red, Green, Blue};
//...
public bool IsRed(Color color){
switch(color){
case Red: return true;
case Green: return false;
}
}
@jamesbascle no, you are right, it was a mistake on my part - it does only capture what it think it needs.
But if say, you want to check if c => person.Name == c.Name
- it is capturing the class containing the property Name
(the person object) because it's really a method of the object (get_Name()
) - if we could explicitly get the backing value being the value that is referenced in the expression (i.e captured explicitly via [person.Name]
), that's where we would see the reduced footprint. That might not be possible or ideal though. However, if we can just gain better control the lifetime and explicitly capture objects or not, that could help quite a bit. I think the biggest piece we would gain from it is explicitly preventing capture on a self-contained expression via []
.
It's a good feature suggestion, and there are quite a few different ways one could go about implementing it. I'm certainly not going to say mine is the best, and based on how the C# language has evolved since I've started learning and even before that, I can say fairly confidently that I trust the design team's decision on how to go about it, if it's something that is ready to be implemented in the next version at all.
@tophallen I think we can both agree on basically all of that. :smile:
You talking about things like const functions?
Dr Diego Colombo PhD
On 28 Jan 2015, at 07:17, Toni Petrina [email protected] wrote:
I would welcome any sort of "const"ness on method parameters. More powerful switch statement that can handle expression non-compile time constants would also help a lot.
—
Reply to this email directly or view it on GitHub.
@colombod I think he's talking about making mutable objects passed to functions or methods unable to be mutated within method scope. I personally think immutable type support would largely scratch that itch, but there are definitely some other cases.
It would likely have to come with some kind of performance hit, unless the logic for statically analyzing whether any of the methods called or properties accessed within the scope mutate the object in any way can be worked out at compile time.
@MadsTorgersen first of all, I'm the biggest fan of val/let/readonly being a marker for immutability!
We already had a discussion at the Xamarin Conference about non-nullable reference types. What do you say about the following syntax:
Declaration:
``` C#
public void MyMethod(string! value1, object! value2)
{
...
}
I can think about two approaches:
- the "!" sign means there is an ArgumentNull check by the runtime and will be used only as method parameter declaration
- the "!" sign means an addition to the type system, just like "?" is for nullable value types. For the second approach, these could be possible usages:
Guaranteed success:
``` C#
string! stringValue = "Hello world!";
object! objectValue = new object();
Instance.MyMethod(stringValue, objectValue);
Usage with null check:
``` C#
if (stringValue != null && objectValue != null)
{
Instance.MyMethod((string!)stringValue, (object!)objectValue);
}
Usage without null check:
``` C#
// compiler check will make sure you don't assign null
object! nonNullableObject = objectValue ?? new object();
object! nonNullableString = stringValue ?? string.Empty;
Instance.MyMethod(nonNullableString, nonNullableObject);
By putting the argument type in the signature of the method, you enforce the programmer to transform his variables into something that cannot explicitly receive the null value. The runtime should check assignments to these data types and will disallow them.
Non-nullable method parameters will be checked by the runtime as well and could result in ArgumentNullException (or maybe NullAssignmentException) that will always occur if you assign a null value to a non-nullable reference type.
@jamesbascle Maybe then rather than bother implementing explicit capture syntax, we just implement explicit no capture syntax, like a keyword on the expression, i.e
C#
var query = customers.Where(const c => c.Name != null);
//or other keywords, 'val' could be one or something else
var query = customers.Where(nocapture c => c.Name != "SomeName");
more similar to the async syntax for expressions, and maybe then there could be more freedom in how to implement the explicitly captured variables in an expression later, or at least, the more I think about various scenarios for it, the less happy I am with both my suggestions and the [name](c) => c.Name == name
syntax proposed by @MadsTorgersen as no option really _feels_ like the C# option.
I really like the idea of having readonly parameters and locals, the less mutability the better. Too bad that we can't make them readonly by default, as that would of course break lots of code.
Although using val
or let
for readonly parameters or locals would result in less "noise" than readonly
, I would still go with the readonly
keyword. The readonly
approach has the advantage that it is both more explicit _and_ ties into a known keyword that has the same meaning. Perhaps there could be a shortcut syntax for the readonly
keyword, similar to how Nullable<T>
has a T?
shortcut.
Some syntax comparisons:
c#
public void Test1(readonly string str1, readonly string str2, readonly string str3)
{
readonly str local;
}
public void Test1(val string str1, val string str2, val string str3)
{
val str local;
}
public void Test1(let string str1, let string str2, let string str3)
{
let str local;
}
public void Test1(string! str1, string! str2, string! str3)
{
str! local;
}
So personally I think the readonly
keyword should be used, with some shortcut syntactic-sugar to make it easy to use.
I like the idea of typed enums, like in Java Enum Types.
This would allow for natural visitor pattern implemented directly in enum declaration instead of conditional switch, true singletons, etc.
Proper Tail Calls
I would appreciate proper tail calls. I know that the 64-bit jitter does some of that.
Loops is a workaround for some cases, but the code potentially looks uglier.
Loops is not a workaround the lack of tail calls for mutually recursive functions.
Or, when programming a continuation-style manner, to achieve elegant backtracking and other techniques.
Tail calls is actually very helpful when calling many higher order functions.
At the least, you can support a [TailCallAttribute] attribute.
Traits would be good to be have if it they could be defined like classes.
trait Zero { public static T Zero() }
trait Unit { public static T Unit() }
trait op_addition { public static T [+] (T,T) }
trait op_subtract { public static T [-] (T,T) }
trait SimpleCalc
inherits { Zero, Unit, op_addition, op_subtract }
trait op_EqualTo { public static T [==] (T,T) }
trait op_NotEqualTo { public static T [!=] (T,T) }
Traits the would be an extended form of constraited generics
Then for example a Summation
extension method could be generic.
T Sum<T> ( this nums : IEnumerable<T> )
where T has trait SimpleCalc
{
T total = T.Zero;
foreach( num in nums )
total = total + num;
return T;
}
Enforced at compiler and runtime (the run cost could be worth it).
It would be also applicable to constructors
has trait { new (Int,String) } // a constructor that takes an int and a string,
Programming languages should be designed not by piling feature on top of feature, but by removing the weaknesses and restrictions that make additional features appear necessary.
Keep switch
construct as it and have a match
construct for pattern matching.
+1 for Code Contracts at language level. I've ever been a fan of Code Contracts since .NET 4 and the DbC principle in general. I wrote about it in many articles.
Unfortunately, Code Contracts in their current implementation didn't spread very much in real-life projects. Imho this has several main reasons:
Code Contracts built into the language would be awesome, because some constructs have been really cumbersome (contracts on interfaces as an example). But furthermore, integration with tooling (VS, StyleCop, Pex, ...) is key to give real value. And the definition of useful contracts on all .NET core methods, because that's the requirement to let static contract checks work. And in my opinion static checking is the essential part to let code contracts succeed, including features like pure checking etc..
Enum generic constraints would be marvellous.
"Duck typing" generic constraints would also be very useful.
Contracts in some way of some sort (mostly boilerplate, not static analysis).
C# 5:
public void Remove(string item)
{
if (item == null) throw new ArgumentNullException("item"));
}
C# 6:
public void Remove(string item)
{
if (item == null) throw new ArgumentNullException(nameof(item));
}
What if possible to drop Exception
after throw
keyword(like Attribute
is dropped while applied):
public void Remove(string item)
{
if (item == null) throw new ArgumentNull(nameof(item));
}
What if possible to drop new
like in some languages:
public void Remove(string item)
{
if (item == null) throw ArgumentNull(nameof(item));
}
What if possible to use kind of ?
or ??
:
public void Remove(string item)
{
item ?? throw ArgumentNull(nameof(item));
// item == null ? throw ArgumentNull(nameof(item));
}
What if possible to get throw ArgumentNull
via import of static function into namespace:
namespace System
{
public static class Exceptions
{
public static ArgumentNullException ArgumentNull(string name)
{
return new ArgumentNullException (name);
}
}
}
What if like try\catch\finally
:
public void Remove(string item)
{
requires //current Contract.EndContractBlock
{
item ?? throw ArgumentNull(nameof(item));
}
contracted
{
//body
...
}
ensure
{
// compiled into some form into body to prevent assignment less then zero
Count < 0 ? throw Argument(nameof(count),"Should be greater then 0");
}
}
RE: Metaprogramming. Have you considered something like the ASP.NET 5 XRE's ICompileModule interface?
What happened to duck typing of interfaces? I realise it's not C# specific, but I'm sure it was part of 4.6, and it would be incredibly useful for shared libraries (such as logging; an ILog interface)
@yetanotherchris assembly neutral interfaces are also an XRE-only thing
@andrewducker +1 for duck typing of generic constraints.
All I have to say is: Yes please.
@MadsTorgersen Array slices are an awesome idea (the current ArraySegment
(I created one for my projects but it breaks as soon as you call an existing API that expects strings, such as double.TryParse(). So it's one of those all-or-nothing kind of things.)
Also, are you guys doing any pointer escape analysis? Implicit boxing of small objects might not be so painful if the allocation was done on the stack.
It would be nice if you could await in getter and setter acessors of the properties using the async-await pattern. In the next release you can await inside the catch blocks, making it happen in getters and setters would be awesome!
@MadsTorgersen For slicing an new operator ..
could used, to discriminate from 2D array access.
a[ 2 .. 5 ] // a[2] to a[3]
It be also applicable as a defining an range. 1 .. 100
@tanghel +1 for using '!' to denote non-nullable reference types similar to '?' for nullable value types. It's clean, concise, and matches up nicely with existing syntax. Of course the semantics of non-nullable reference types is another matter, but I like the syntax.
@ErikSchierboom val would be like 'readonly var', so not for explicit types. there, readonly could stay.
a.k.a.
string example = "";
readonly string example = "";
but
var example = some.Funky().Query().FromLinq();
val example = some.Funky().Query().FromLinq();
i personally never use explicit types for variables.. only var everywhere. i'd love to instead use val everywhere.
I'd like to see some nice syntax for IEnumerable
my preferred syntax would be T*, but given the unsafe {} c++ style pointers there, that won't work.
@davepermen Ah, then it makes a lot more sense! val
is thus an alternative for var
. I would then prefer let
over val
, as the difference between val
and var
can be quite hard to spot.
that's true. but var is short for variable, val short for value. let is .. well.. nothing.. :)
but yes, readability might be an issue.
Something that is missing is syntax for accessing the field or property of a class. This is often done in linq chains, and is usually done using an expression:
//here x => x.name is an expression and reflection is used to find out which property is accessed
myDatabaseTable.select(x => x.Name);
//it could look like this
myDatabaseTable.select(DatabaseTableClass::Name);
ClassName::FieldName
would be syntaxt sugar for typeof(ClassName)).GetField("FieldName")
.
select()
could be defined as
public static TResult select<TInput, TResult>(this TInput self, FieldInfo<TResult> field){
return field.GetValue(self);
}
Note that I am assuming FieldInfo is generic, which it isn't today, but should be (just like Type should be generic, like Class is in Java)
Regarding lambda capture lists:
In a way the most useful annotation would be the empty
[]
, making sure that the lambda is never accidentally modified to capture _anything_.
A simple, targeted solution to this is to have an alternative lambda 'arrow' syntax for non-capturing functions.
users.Select(user -> user.Active); // "->" requires non capture
Developers and IDEs can migrate existing code where possible, after which the guarantee is enforced.
It's not clear to me how copying a reference type would be enforced if a capture list allowed specifying copying. Would copy constructors have to be added to the language as well?
let
reminds me of the days when I was writing code in VB6 (fond memories), but I think I prefer it to val
as it's significantly different enough from var
that you could easily see whilst scanning code that the variable in question is readonly. I also think that let
doesn't convey well enough that the variable is readonly.
The only alternatives I've thought of are rvar
(readonly variable) or rloc
(readonly local) or rov
(readonly variable). Though I wouldn't consider any of those to be ideal, I think they convey the point of a readonly variable better than let
.
Perhaps val
would also be fine, it certainly links it to the existing var
keyword so it has that going for it. And now that I think of it, I did not have any problem with val
and val
doing the same thing that is proposed in Scala.
We've done one project in GoLang now and, despite some crippling design flaws, there is one area that it shines -- concurrency, ie. channels/goroutines. They have the same liberating effect on parallel processing that the property/method/events model has on component development. In other words, the syntactic sugars buys you a lot.
C# Task parallel library works as a weak substitute. You have to resort to block processing to get 1/2 the performance that GoLang gives you on scalar channels naturally. And it only works on a specific subset of problems.
We're done with GoLang due to its other flaws but we'd love to see C# copy channels/goroutines.
ps - If you think existing lambas and async/await get you the same effect, you need to use GoLang for a project to see the difference. It's not even close.
I sometimes see Japanese programmers are confused on distinguishing val and var in Scala, even though they are professional IT developers for years. It is difficult for Japanese to make out deference between L and R.
@joshuaellinger Could you explain what exactly makes channels so much better than async
-await
? Is is the support for asynchronous sequences?
@MadsTorgersen what about try/catch/finally aggregation?
Instead of:
``` C#
int result;
try
{
result = GetValue();
}
catch (Exception ex)
{
HandleException(ex);
} finally
{
DisposeResources();
}
... you could write:
``` C#
var result = try GetValue catch HandleException finally DisposeResources;
And the elongated version could look like:
C#
var result = try () => GetValue()
catch (Win32Exception ex) if (ex.NativeErrorCode == 0x00042) => HandleNativeException(ex)
catch (Exception ex) => HandleException(ex)
finally () => DisposeResources();
The trick would be to enable return values on a try block, as well as support lambda expression on try/catch/finally. As long as it's a one-liner, the resulting code looks much cleaner.
@tanghel Yes, Scala has done this for years without issues. It's kind of weird in C# though, because try
(and as proposed above, switch
) would turn into an expression, but if
would still be a statement. They either need to go the whole way or drop this proposal, imho.
@Giftednewt: What about def
instead of let
?
@soc yes you are right, but you can use the conditional operator (?:) as an expression and assign it to a result variable. Changing the if clause to expression would most probably mean to include a then keyword as well. We'll see
@tanghel
but you can use the conditional operator (?:) as an expression
The point is achieving some kind of consistency, not the lack of work-arounds.
Changing the if clause to expression would most probably mean to include a then keyword as well.
I don't see how this would follow from making if
an expression.
@igor-tkachev I think that as def
is what's used in languages like Ruby and Python to define a method, it could cause some confusion. I personally would stick to val
, or maybe something like imm
or imut
if you wanted to be very explicit in its purpose?
@soc you have to mark somehow that the if clause has ended and that you're expecting a result expression, that's what I meant. Or maybe I don't see a more elegant way of doing it
conditional operator
``` C#
var result = value == 10 ? true : false;
hypothetical if expression
``` C#
var result = if value == 10 then true else false;
@MadsTorgersen
@Romoku: I'd love to get non-nullable reference types into the CLR. It seems a tall order even there: what's inside an array of non-nullable reference type when it's first created? etc.
Why not doing something like the D array initialization?
This would create an array with all items set to an empty string.
string![100]! a = string.Empty;
@tanghel (???) C# already has a syntax for if
/then
/else
, it looks like if (...) ... else ...
and works perfectly fine.
What is default(string!)
going to be?
@orteipid Groovy and Nemerle use def
to define immutable variables. Also Nemerle uses it to define local functions and I did not notice that it's confused.
@soc yes you are right, my bad. C# enforces the brackets for the condition part of the if clause so you don't need a then keyword
I think there's a few interesting additional rows in your table of 'kinds of types' that you could consider homogenizing into the same approach (following your lead, some syntaxes are just strawman speculations):
| Type | Denote | Create | Match |
| --- | --- | --- | --- |
| Option (Nullable<T>
) | T?
| explicit cast? | !x
|
| Sequence (IEnumerable<T>
) | T*
| (list, array, obvs. existing yielding generators; yielding lambdas? () => { yield return x; }
) | a :: b
|
| Promise (Task<T>
) | T~
| (? - obvs. async methods; async lambdas? async () => x
? () ~> x
?) | await x
|
Something of a monadic theme developing here...
I'm very happy to see async sequences on the table. This is a big pain point for me right now.
@RichiCoder1 I'd argue that keywords on parameters is the C# way. Extension methods, varargs, ref
, and out
parameters are all keywords on parameter lists. Did I miss any obscure ones? You could select better keywords to be certain. That does leave the question of an empty capture list however... Perhaps (c, noscope) => c.Name == "Frank";
:-)
@tanghel,
Next thing you know, you’ll be proposing to change var into Dim and remove the trailing semicolon… I think there’s already a language for that from Microsoft. FWIW, you could simplify your code example from
var result= value == 10 ? true: false;
to
var result = (value == 10);
Sent from Windows Mail
From: Traian Anghel
Sent: Wednesday, January 28, 2015 10:39 AM
To: dotnet/roslyn
@soc you have to mark somehow that the if clause has ended and that you're expecting a result expression, that's what I meant. Or maybe I don't see a more elegant way of doing it
conditional operator
var result= value == 10 ? true: false;
hypothetical if expression
var result = if value == 10 then true else false;
—
Reply to this email directly or view it on GitHub.
The functional style of programming often requires the use of functions within a lexical scope & with access to the closing state (i.e. closures). C# has no formal way of declaring named internal functions, however can be approximated with:
Func<double,double> square = x => x*x;
It would be nice to have basic type inference on the return value and make use of type annotations in the arguments rather than in the delegate definition (so that it easier to read and implement):
var square = (double x) => x*x;
Ideally one could forego the type annotation entirely and a delegate type mapping is inferred from the 1st usage.
Another issue with the above is that cannot apply recursion, as the lambda expression is not named until assignment.
Having a syntactic way to define lexically scoped functions within code blocks would be beneficial. Could do:
fun square (double x) => x*x;
OR
fun factorial (int n)
{
return (n == 0) ? 1 : n * factorial(n-1);
}
The above examples are contrived, as more often would want to declare an internal function to assist in the implementation of a method, accessing the code-block's context.
Short of new syntax, avoiding the required Func
@pdelvo Yes, that's an important question. The type itself should define what it's default not-null value should be. This might IMHO either be a fixed value (like string.Empty) or a new instance (using its default constructor maybe?). Therefore it's important to know if a reference type is "default(T)"able.
@jameshart I think that T* is confusing, because C# allows pointers to be defined with "T*".
@fubar-coder: Why not doing something like the D array initialization?
This would create an array with all items set to an empty string.
string![100]! a = string.Empty;
That sounds like a good idea. I am not all that familiar with D.
+1 For either "enhancing" the switch statement for conciseness, or introducing a match construct that achieves the same goal.
+1 For pattern matching.
@jwooley
Next thing you know, you’ll be proposing to change var into Dim and remove the trailing semicolon… I think there’s already a language for that from Microsoft.
Please look above that. What I actually proposed was try/catch/finally blocks as lambda expressions.
FWIW, you could simplify your code example
Of course it could be simplified. But then it could not have served as a proper example for comparison
Out of curiosity, would something like the default parameter approach work for the capture list?
var name = GetName();
var query = customers.Where(c => c.Name == name);
Would become:
var name = GetName();
var query = customers.Where((c,n=name) => c.Name == n);
Might be closer to something people are used. Also a couple of questions that popped up when I saw the method contracts. While I want this in the language, here's the questions that I would have:
1) Would we be able to define this at the interface level as well as the class level?
2) What sort of exception would be thrown? If it's built in (a RequiresException) then that's simple enough but would something along the lines of this work so that we could specify?
public void Remove(string item)
requires item != null throws ArgumentNullException
ensures Count >= 0 throws MyCustomException
{
...
}
Otherwise I could see issues with attempting to port older code to this approach.
I think the let
suggestion for readonly
makes sense, and I prefer it to val
, as it is easier distinguish from var
, and matches up with F#/Swift.
I'd also like to see a bit of syntactic sugar added. Which is, allow object notation using JSON-ish syntax (or close), as { }
already has meaning in C#:
var obj = new { key : "Andrew", score: 1.0, openSourcerererer : true }
Mainly, I find that as I switch between JS and C#, I type =
when I mean :
and vice-versa.
Regarding let
vs val
-- LINQ expressions already use let
and are effectively readonly as far as I can tell. Would make sense to reuse the word instead of introducing additional grammar.
@ryancerium I'd argue back that pretty much everyone one of those keywords is shaping a parameter or parameters. Capture, while specifying what should be included, does not technically have much if any relevance to parameters.
+1 to a first class code contracts model and not within the code body. The old contracts support in .NET is painful to work with and it makes the code noisy. No one wants to have to use a post-compiler, they want it to just work. It would be a big win to have a clean declarative syntax, even one that allowed me to define constraints externally rather than inline.
Bringing contracts to the language would be great but I don't see why I would switch away from Code Contracts if the implementation is not complete. There are definitely things that I get with the current implementation of Code Contracts that I would want to keep in my development process.
From a correctness point of view I really like the static analysis tool. While it has bugs (which I can now go attempt to fix https://github.com/microsoft/codecontracts ) it is very nice to know you have an extra check preventing some runtime errors from happening at all. With respect to ease of development, having requires and ensures is great but without object invariants I would need to write a lot of redundant contracts. Another feature I get from the current Code Contracts implementation is performance (nothing major but still nice to have) as I can have preconditions that are within my private surface removed from my builds while leaving the public surface contracts in.
I'm sure I could think of other little things here and there but really while I like the idea of adding DbC to the language I just want to make sure that I don't have a reduction in the functionality and tools I have today. If it is not possible to achieve feature parity I would really like to see the two systems be compatible with each other.
On the subject of new additions, what ever happened to extension properties?
I have to say I'm not a fan of using "let" to mean that a variable is read-only. I'd much rather having something slightly longer that's entirely clear.
readonly var bob = new Person("Robert");
Seems clear to me without requiring massive ceremony.
On "Working with data" a problem I regularly encounter is functions that look pure (and was suppose to be), but are not in fact pure which result in bugs slipping in. Being able to give a function a pure attribute that did side-effects verification would eliminate this class of errors.
As for immutability, I'd let things be marked "immutable" if every property was marked either readonly (primitives) or immutable (objects).
Arrays would be excluded from this, but I almost never use them, so it's not a massive loss to me. You get 99% of the functionality, in a clean manner.
Absolutely with you on opt-in purity (and immutability)
I must say that it's amazing that we are having this public discussion! Feels great to be part of the process.
Perhaps it would be wise to create separate issues for the suggested features. At the moment it is becoming quite hard to follow a discussion of a specific feature as all discussions overlap.
static linking instead of IL merge
+1m Every .net library developer just squealed with delight :)
For a bunch of us over at https://github.com/aspnet/XRE/issues/819 this could not come fast enough.
So regarding types - why not implement an automatic mapping set of extensions/utilities that allows for mapping objects based on names/types that allow for options/overloads to do so a compile time or run time. With various interfaces to overload if necessary. There are lots of solutions out there to do this in various ways, but it would be nice to have a standard language implementation to do so.
viewModelObject m= domainobject
Just a thought.
@RichiCoder1 I suppose that the scope parameters are more like parameters to a constructor than they are to the lambda function itself. I mentally convert them to "things inside the lambda" instead of "parameters to a function".
I'm going to change the lambda to a pile of crap and change the captured parameter to value types so that they make more sense in terms of reference/value capture semantics.
The newly-rewritten-terrible-lambda
``` C#
var number = GetNumber();
var maxAge = 0;
var query = customers.Where(c => {
maxAge = Math.max(maxAge, c.age);
return c.Number == number; } );
gets rewritten to
``` C#
class LiftedScope : Func<Customer, bool>
{
int number;
ref int maxAge;
LiftedScope(int number, ref int maxAge)
{
this.number = number;
this.maxAge = maxAge;
}
bool Call(Customer c)
{
if(c.Age > maxAge)
maxAge = c.Age;
return c.Number == number;
}
}
I personally prefer writing
``` C#
var number = GetNumber();
var maxAge = 0;
var query = customers.Where((c, value number, ref maxAge) => {
maxAge = Math.max(maxAge, c.age);
return c.Number == number; });
``` C#
var number = GetNumber();
var maxAge = 0;
var query = customers.Where([value number, ref maxAge](c) => {
maxAge = Math.max(maxAge, c.age);
return c.Number == number; });
mostly because the square brackets always make me think of arrays or subscripting. The fact remains that the =>{} syntax from C++ is pretty awful, albeit powerful. I'd actually be interested to see what the C++ design committee's design notes on the topic were.
There are clearly too many features being requested in this thread for any meaningful movement forward on any particular issue.
F# had this problem as well, so they created _a voting mechanism_, that includes showing which features are actually tractable for the team to implement:
https://fslang.uservoice.com/forums/245727-f-language
This seems like a more structured approach than dumping every idea into a single thread.
@jonschoning They mention in the notes that they'd like to introduce a UserVoice for that exact reason ;). People have just been piling onto the thread.
So the #1 performance problem with C# in a lot of domains (e.g. games) is battling the GC. Part of this could be helped by un-gimping value based programming (which you've mentioned a bit already), part of it could be helped by un-gimping array programming (which you've mentioned a bit already). Part of this could be helped by un-gimpling lambdas (allow them to be stack allocated).
Should C# also allow some more explicit memory control and/or control over the GC? E.g. allow you to allocate classes on the stack with a keyword and get compile-time errors when it's unsafe? This would require functions to need some kind of meta data compiled into them if arguments escape the stack etc...
Maybe allow you to tag functions with "No alloc" and make sure it transitively gives an error on anything that allocates. Maybe have a pass through the standard libraries and provide overloads to common functions that don't need to allocate (e.g. why can't I convert a number to a string without allocating? That seems kinda ridiculous. I mean obviously it would need to be a string builder... ).
Maybe some kind of programmer-in-the-loop GC? Let the programmer call some kind of "do GC work incrementally" every frame? This would help many interactive applications where you're updating at 60Hz. This would unfortunately require that you mandate some kind of incremental GC to be implemented in the runtime on top of the current (batch-oriented) one, as System.GC.Collect is completely unsuitable (for several reasons... it does too much work at a time, it promotes things to older generations, etc.)
@ErikSchierboom agreed! Thanks C# team!
Entity Framework or any other Reflection based Framework should have option for generating C# code for better performance. EF or N hibernate spent most of the time in reflection like mapping the column or mapping the result coming back from the database. We all know SQL DataReader 10 times faster than EF (see link https://github.com/StackExchange/dapper-dot-net). If EF or Nhibernate have option for generating mapping while compiling it will improve the performance. For example
dbContext.Person.Where(t=> t.Country =="USA").ToList();
The above statment can be optimized by C# compiler and generate SQLDataReader Mapping. Instead of reflection.
Other framework AutoMapper is usefule for DTO mapping. But if there is a way we can utilize Rosyln and C# compiler and compile time it can generate static mapper instead of dynamic reflection based mapping then it boost the performance.
I wrote a basic proposal for non-nullable reference types. I need to flesh it out more.
EF and NHibernate do generate IL and proxy-types though. The slowness is from other reasons.
I would rather apply code contracts as attributes
[Requires(item != null)]
[Ensures(Count >= 0)]
public void Remove(string item)
{
...
}
or
[Requires(item => item != null)]
[Ensures(this => this.Count >= 0)]
public void Remove(string item)
{
...
}
It's almost like you looked at Language-Ext (https://github.com/louthy/language-ext) and went "Yeah that would be nice" ;-)
Which I am not complaining about at all. This looks like my C# wishlist coming true here so that's awesome. Especially: 'the null problem', records (please make them immutable by default, and make them non-nullable by default), proper tuple support, pattern matching and language list/dictionary support (again preferably with ImmutableList and ImmutableDictionary).
Code contracts would be nice, but I think taking it a bit further and having a lightweight syntax for generating dependant types would be a much nicer approach:
struct OneToTen = ensures int in (1..10)
void Foo(OneToTen value)
{
...
}
That would be an off-the-scale amazing feature for C#, and really help with bringing large code-bases under control as well as improving the declarative nature of the language (and therefore tooling support).
Great work though, it looks very promising :)
+1 @Maxwe11 for attributes
@tophallen I like that suggestion, it reminds me of the string interpolation, $"Hello {person.Name:format}"
() => {person.Name:val} = "Something new"; // compiler error, or just a local version?
() => {person.Name:ref} = "Something new"; // as normal
@MadsTorgersen I guess that a goto
inside a switch
statement with pattern matching should not be allowed/supported?
I'd like to suggest creating a separate UserVoice for the C# language. I find my votes to be spread pretty thin between all the different categories on the current Visual Studio UserVoice,
@tr8dr
The functional style of programming often requires the use of functions within a lexical scope & with access to the closing state (i.e. closures). C# has no formal way of declaring named internal functions, however can be approximated with:
Func
square = x => x*x;
It would be nice to have basic type inference on the return value and make use of type annotations in the arguments rather than in the delegate definition (so that it easier to read and implement):
The type inference part of that is already possible:
C#
var square = fun( (int x) => x * x );
https://github.com/louthy/language-ext/blob/master/LanguageExt.Tests/FunTests.cs
@jvlppm @MadsTorgersen I'm also interested in async iterators. (Related discussion) However, it's worth noting that Rx actually does provide a nice form of async iterators already via overloads of the static Observable.Create
method.
Furthermore, one of the problems the language team would have to overcome to make this feature the most effective is how to yield from within closures. See in my GIST example (link above) that I call observer.OnNext
from within a call to Subscribe
. That would be a very important feature, IMHO.
@louthy yes, have seen your lib. Very nice. Was looking to see some of it formalized into a future version of C#.
Hi,
I think having a first language support for decorators could be extremely useful,
this pattern is already in so much use, yet it always creates a lot of boilerplate.
Kotlin solves it quite nicely with delegation.
http://kotlinlang.org/docs/reference/delegation.html
class Decorator(instance: Decorated) : Decorated by instance
{
}
var a = new Decorator(new Decorated());
a.SomeDecoratedMethod();
static linking instead of IL merge
^ THIS :+1: :shipit:
@ssylvan
Maybe allow you to tag functions with "No alloc" and make sure it transitively gives an error on anything that allocates. Maybe have a pass through the standard libraries and provide overloads to common functions that don't need to allocate (e.g. why can't I convert a number to a string without allocating? That seems kinda ridiculous. I mean obviously it would need to be a string builder... ).
There was a thread on the Roslyn discussion board that talks about similar ideas (you'll need to read through the whole thing!)
One of the ideas was having a [HotPath]
attribute that indicates that the method shouldn't allocate.
Also you should take a look at RoslynClrHeapAllocationAnalyzer, which uses Roslyn to produce some analysers that highlight several common _"hidden allocations"_
I'd like to see new language syntax to simplify creating immutable data structures. Having to write a constructor with lots of parameters soon becomes a pain to maintain and document. Maybe something like this:
immutable class Person
{
public string Name{get;set;}
public int Age{get;set;}
}
The setters are only available during construction, or within the class constructor. The existing property initialization syntax could be used during construction: Because the class is immutable its properties are also immutable. They're read/write during construction, and readonly any other time.
var person = new Person {Name = "Fred", Age=10};
But the properties would be readonly after construction completes, so you couldn't write:
person.Name = "Bob";
afterwards.
The immutable class could still have a constructor, so that it can set properties not required by the user. Eg:
immutable class Person
{
public Person()
{
this.ID = Guid.NewGuid();
}
public string Name{get;set;}
public int Age{get;set;}
public Guid ID{get; private set;}
}
Also, in the constructor you would validate any properties that have been initialized. However, I suspect this might be difficult to actually implement as it requires a form of two-stage construction whereby the class in constructed, its immutable properties are assigned, and then the constructor is run.
I'd go for that - except that for it to be immutable, every property should be readonly, and all reference types used should also be immutable:
immutable class Person
{
public Person()
{
this.ID = Guid.NewGuid();
}
public readonly string Name{get;}
public readonly int Age{get;}
public readonly Guid ID{get; }
}
This matches the pattern we see with static classes (which is a trigger for compile-time checks), and should be relatively simple to introduce.
const
is already used for locals, and I suppose readonly var
for locals would do the same. Anyway, it lacks type inference.
const int x = 1; //OK
const x = 1; //Error
Every once in a while I get frustrated by the missing const
as a valid modifier for method parameters, as well as the type inference for local consts.
As I see,
int Foo(const int x)
{
const y = 5;
return x + y;
}
would be much more consistent than
int Foo(readonly int x)
{
const int y = 5;
return x + y;
}
or
int Foo(readonly int x)
{
readonly var y = 5;
return x + y;
}
I'm with @AdamSpeight2008 on this. As pattern matching will have different semantics (particularly order of specifications being significant, and ensuring exhaustive checking (hopefully)) they should be a different feature. Using a keyword "match" seems appropriate.
Ideally make it an expression rather than a statement too.
int? x;
var x = match (x) {
case ????: // How to handle the "Maybe" (Haskell terminology) case here??
// Use n (no need for break here, as "run through" can't occur in match
case null:
// Handle null here
};
The above example indicates a primary motivation - exhausive null checking of optional types. How do you write the first case pleasantly?
Also, bear in mind something like guard clauses in Haskell. These can be incredibly useful in Pattern Matching.
@MrDoomBringer - Requires and ensures are necessary in the presence of overridding. The requires applies before calling, the ensures afterwards.
Please, please, study Eiffel's approach carefully wrt Design by Contract - they've encountered and solved many issues here and would be silly to make the same mistakes again.
Just a thought about non-nullable reference types:
Why not combine monadic approach of Option/Maybe with non-nullable CLR type?
Example of already existing type with special rules is Void, which, being a valid CLR type, cannot be accessed directly using C# semantics.
In case a non-nullable types were introduced in CLR, C# could permit deriving from them only by monadic types. Moreover, introduction of these types would also enable easier means for the language to support exhaustive pattern matching on them and help in matters like array initialization. Some rules could be applied to theses types, like enforcing implementation of _default_, _SelectMany_ and _Select_ in order to use inside LINQ query syntax, etc.
Something like (wishful thinking, by no means complete and/or right):
//'monadic' means it implicitly implements base non-nullable Monadic<T>
// it also specified the class is sealed for external inheritance
// symbols inside parentheses specify the possible subtypes of this type
public monadic class Option<T>(Some, None) where T : class
{
//'value' classes implicitly derive from enclosing monadic class
value class Some
{
public override Monadic<U> Select<U>(Func<T, U> selector) { ... }
public override Monadic<U> SelectMany<U>(Func<T, Monadic<U>> selector) {...}
public override Monadic<S> SelectMany<U, S>(
Func<T, Monadic<U>> selector,
Func<T, U, S> projection)
{
...
}
//additional implementations of Option<T> and Monadic<T>
}
value class None
{
//implementation of Option<T> and Monadic<T>
}
public static operator default Option<T>() { return None.Instance; }
}
This also would allow to deal with the backward compatibility of BCL, by clearly separating null-safe (generally side effect-safe???) API's from the legacy ones. i.e., there are many pseudo-safe API's appearing in each new version of .Net, such as TrySomething instead of Something, where you can still use both, but the newer code will probably use the new version. IMHO, monadic return values combined with pattern matching would be much better in this case.
Another idea (not credited to me) is to create a mechanism to help fluent APIs.
https://github.com/dotnet/roslyn/issues/155
Are you still considering yield foreach
?
see http://research.microsoft.com/en-us/projects/specsharp/iterators.pdf
I would still like some compiler-love for Interfaces.
interface IFoo { string Name; int Age; }
var me = (IFoo) new { Name = "Metro", Age = 56 };
If the compiler knows the source type and can tell it would support an Interface, it could generate the proxy for the interface. In the case on an unnamed object, I'd like to see the ability to new an interface directly.
interface IFoo { string Name; int Age; }
var me = new IFoo { Name = "Metro", Age = 56 };
I know it's never going to happen, but I've always thought that casting in C-style languages could be improved, and in C# made a bit more consistent. For example, rather than:
Person p = (Person)x;
Person p = x as Person;
bool isPerson = x is Person;
We could write:
Person p = cast<Person>(x);
Person p = as<Person>(x);
bool isPerson = is<Person>(x);
Yes, it's more verbose, but it provides a consistent approach to type conversion. Plus, it's slightly more verbose syntax draws more attention to what's going on, much like the C++ cast operators do.
Another ++ for method contracts! I always wanted code contracts to become more elegant. We could almost completely replace the need for unit testing with them.
@foxesknow: You can already do that with methods and using static
.
@leppie - sure, but then it's a function call that maps to a cast/conversion that maps directly to IL rather than a language primitive that maps directly to the IL.
@foxesknow @leppie You can. What you can't do is check if a variable is of a given type and assign it at the same time. I'd love to be able to write:
if(myObj.TryCast(out TextBox myTextBox)
{
myTextBox.Text = "Aha!";
}
But because you can't create an "out" as part of the method call (you have to create it in advance), which always makes this feel clumsy.
This was supposed to be coming with Declaration Expressions, but those were dropped from C# 6. I'm hopeful that they will come back with C# 7!
@foxesknow I suspect that the function would probably be in-lined and effectively the same as built-in compiler support.
@foxesknow what @msauper said :)
With some overloads you could even turn it into a nop
.
@msauper - maybe, maybe not :-)
@andrewducker (myObj as TextBox)?.Text = "Aha!";
is cleaner IMO (assuming you can use 'elvis' that way)
That doesn't work if there are multiple lines inside the curly braces...
@leppie What will be the result of such expression? Null? And what if you'd like to initialize a number of properties?
@andrewducker @galenus then dont be lazy :) 1 extra line wont shorten your lifespan significantly.
@leppie Please don't be insulting. We're trying to find ways to improve the language. Denigrating others for making suggestions isn't going to help.
@andrewducker I am not being insulting. You can do this already with something like:
``` c#
static void With
{
T t = o as T;
if (t != null) a(t);
}
With
...
});
``` c#
static void Is<T>(this object o, Action<T> a)
{
T t = o as T;
if (t != null) a(t);
}
myObj.Is<TextBox>(tb => {
...
});
My point is many of the suggestions are needlessly redundant.
@leppie Accusing others of laziness is inherently derogatory. If you don't like the proposal, and believe that saving the one line per usage of the different approach is unnecessary, then that's fine.
(And showing other people a better way of doing things is great.)
But calling other people lazy is not.
@leppie pointing out that you can write a method to do something rather than add a feature to the language seems a bit of a cop-out. By that argument we could drop foreach and just replace it with an extension method.
Hey, who needs while - it's just an if and a goto..!
@foxesknow No need to over react. People should consider what should really make it as a core language feature, and what could be a potentially great NuGet package.
@foxesknow: You would not be able to use in a generator then (aka yield return). But this is inherently a problem for languages without continuations and hence the incredible difficult (and well done) implementations of generators and async code.
Thanks for all the comments everyone! I'll be closing out the issue now, as the discussion is off in many directions and probably hard to productively follow for most. Many of the features discussed in the design notes are now up as individual issues, and I encourage continuing the discussion there.
It is astoundingly great to see such excitement around the next version of C# - even at this very beginning of its design cycle. The creativity and insights coming out here on GitHub are just amazing, and I'm very happy we move here. It's going to be a wonderful time going ahead! Thanks again!
Mads
How about an auto property with a lazy backer. That would be nice.
I think it would be good to have something I call it Inline type declaration:
For example think of an action in web api. You want to define a Data Access Object but defining a class and use it once (in an action) is somehow expensive:
``` C#
public class SampleDao
{
public int a {get; set;}
public string b {get; set; }
}
public class SampleController : ApiController
{
public SampleDao GetSample()
{
...
}
}
It can be more simpler by inline type declaration:
``` C#
public class SampleController : ApiController
{
public {int a, int b} GetSample()
{
...
}
}
@alisabzevari What I usually do if I have a web api that returns a projection (or DAO) that nothing else in C# uses, is that I declare it object
and return an anonymous type.
public object GetSample()
{
return new { a = 4, b = 2 };
}
I would agree this is not the best self-documenting code, but it works and avoids boilerplate code.
@jods4 I use this technique too. But the problem is we can't write strongly typed unit tests for these apis.
You don't have to, as you know that it is going to be serialized over the wire, test it as an XML object or a json object using the serializer your API uses, and validate it that way. Or test it as a dynamic object, by pulling in the Microsoft.CSharp reference.
From: Ali Sabzevarimailto:[email protected]
Sent: 1/31/2015 21:57
To: dotnet/roslynmailto:[email protected]
Cc: tophallenmailto:[email protected]
Subject: Re: [roslyn] C# Design Notes for Jan 21, 2015 (#98)
@jods4 I use this technique too. But the problem is we can't write strongly typed unit tests for these apis.
Reply to this email directly or view it on GitHub:
https://github.com/dotnet/roslyn/issues/98#issuecomment-72352977
I try to consider web apis as normal classes and try to write them the way
they are normal classes; Not classes that are designed specially to work
with http. I think they could be used as logic layer classes in different
contexts. That's why controllers in MVC6 are not required to inherit from
Controller class.
On Sun Feb 01 2015 at 10:24:52 AM tophallen [email protected]
wrote:
You don't have to, as you know that it is going to be serialized over the
wire, test it as an XML object or a json object using the serializer your
API uses, and validate it that way. Or test it as a dynamic object, by
pulling in the Microsoft.CSharp reference.
From: Ali Sabzevarimailto:[email protected]
Sent: 1/31/2015 21:57
To: dotnet/roslynmailto:[email protected]
Cc: tophallenmailto:[email protected]
Subject: Re: [roslyn] C# Design Notes for Jan 21, 2015 (#98)@jods4 I use this technique too. But the problem is we can't write
strongly typed unit tests for these apis.
Reply to this email directly or view it on GitHub:
https://github.com/dotnet/roslyn/issues/98#issuecomment-72352977—
Reply to this email directly or view it on GitHub
https://github.com/dotnet/roslyn/issues/98#issuecomment-72354287.
@MadsTorgersen writes:
... there's a long-standing request for non-nullable reference types, where the type system helps you ensure that a value can't be null, and therefore is safe to access.
Yes! Please have a look at Ceylon and how it handles null. Simply put: All types are non-null by default. If you want null
, you explicitly declare it with the ?
operator. Once you've done an exist
check against that variable, it's guaranteed not to be null
.
Now, I know this won't fit with C# and its "null by default" scheme, but being able to assert and from then on guarantee that a given variable is not null would be extremely powerful.
@asbjornu I think that non-null by default would very likely break existing code.
@AdamSpeight2008 That's why I wrote the following:
Now, I know this won't fit with C# and its "null by default" scheme, but being able to assert and from then on guarantee that a given variable is not null would be extremely powerful.
Any predictions on whether we're likely to see a new CLR for C#7/VB14? .NET 5.0 at last?
C# could accept an exclamation point after the type definition, indicating that the reference type is not nullable.
And this could be just a compile time check.
How would it work:
public static void Test(object! obj) {
... // code
}
Would compile to:
public static void Test(object obj) {
if (obj == null)
throw new ArgumentNullException(nameof(obj));
... // code
}
object! a; // Build error
object! inline = new object(); // OK
object canBeNull = new object();
object! wouldBeNull = canBeNull; // Build error
object! cannotBeNull = canBeNull!; // OK
The last line would be compiled to something like:
if (canBeNull == null)
throw new NullReferenceException(nameof(canBeNull));
object cannotBeNull = canBeNull;
@jvlppm One item from your examples would only be an error if it's a field.
class T {
object! a; // build error
void M() {
object! x; // no build error
}
}
Also note that a non-nullable type could not be used for the type of a field in a struct
.
@sharwell why it would not be an error? In my sample I was expecting that to be an error.
Not Nullable references must initialized.
And it should integrate well with existing code / assemblies.
@jvlppm @sharwell actually, it shouldn't be an error, because in many situations initialization cannot be made fit into a single line. You wouldn't limit usage of non-nullable types to one-line initializables, right?
Yes I would, because if initialization was done later, the reference would have no value until that point.
And you can always do this, in case initialization is not short:
object! x = GetValue();
object! GetValue() {
object a = null;
... // Some initialization code
return a!;
}
Also, inside methods, you could convert to non nullable in a single line.
object objectUnderConstruction = null;
... // Some initialization code
object! notNull = objectUnderConstruction!;
@jvlppm your field's value may depend on constructor arguments, in which case the GetValue()
method (which should be static, BTW) will not help much.
OK, I see.
First, don't be harsh on newcomers, the above sample have the declaration and method together for reading purposes, they are not necessarily on the same scope. The static keyword was omitted on purpose, because it is not a requirement for this feature. This should not be under discussion, since it only distracts the reader, and shifts the focus away from my humble proposal.
So ignoring primary constructors, field initialization could be delayed to constructor, requiring that they are initialized before usage / method calls.
class Test {
object! notNull;
Test() {
object x = notNull; // Error, usage of notNull before initialization
MethodCall(); // Error, non nullable references must be initialized before method calls.
StaticTest(this); // Error, non nullable references must be initialized before this.
notNull = CreateObject(); // OK / Required initialization
MethodCall(); // OK, all non-nullable references already initialized
}
static object! CreateObject() {
object a;
... // Initialization code
return a!;
}
void MethodCall() { }
static void StaticTest(Test a) { }
}
I guess this way it should work, and not be so limited on initialization.
@jvlppm First of all, sorry if my remarks sound harsh - that was definitely not my intention.
As of initialization problem - I believe some kind of user extendable mechanism for default
operator overloading could help with this matter.
Let's say, you would only be allowed to use the !
identifier with types having the default
operator overload or static method like public static operator Lazy<MyType> default() ...
accessible in the scope of your code.
I would really like something like a "dot assignment" operator, which I think should look something like this:
instead of using
string s = "Hello World!";
s = s.ToLower();
I would like to use
s .= ToLower()
.
I know, this isn't much, but i really like to keep my code short in some lines and this would really help.
And an other operator I would really like to see is the following one:
Instead of using z = Math.Pow(x, y)
I would hope for something like z = x ** y
.
I know that the star-character is used for pointers, so I have also this alternative to propose: z = x \ y
(I have noticed, that there is no "Backslash-operator")
Excuse me for my bad English - I am working on it :)
Thank you very much,
Unknown6656
What about javalike interface initialization? something like:
interface IHasPropertyName{
string Name{get;}
}
new IHasPropertyName{Name = "Alice"};
And additionaly
interface IHasPropertyName{
string Name{get;}
}
interface IHasPropertyAge{
long Age{get;}
}
new IHasPropertyName,IHasPropertyAge{Name = "Alice", Age=21};
So, it will
public var CreateAlice(){
new IHasPropertyName,IHasPropertyAge{Name = "Alice", Age=21};
}
And whern we see CodeHint where will be method signature
public AliceType CreateAlice<AliceType>()
where AliceType:IHasPropertyName,IHasPropertyAge
and another feature is using TypeConstraint with only interface and properties to use TypeConstraint like a type
public AliceType CreateAlice<AliceType>()
where AliceType:IHasPropertyName,IHasPropertyAge
{
new AliceType{Name = "Alice", Age=21};
}
await/async...
they are too ugly...
why we need to use async and Task> type?
why we cannot to use await transparently?
see
calss A{string val;}
class B{A a;}
class C{B b;}
A loadA(){
return await loadFromSlowSource();
}
B getB(){
var b = new B{a=loadA()};
//some code in getB
return b;
}
C getC(){
var c = new C{b=getB()};
//some code in getC
return c;
}
void main(){
var = getC();
//some code in main
Console.WriteLine(c.b.a.val);
}
When we call await loadFromSlowSource();
we create async task what works asynchronously untill we do not access any A instance fields.
And if loadFromSlowSource work too long some code in getB
, some code in getC
and some code in main
will execute parallely with loadFromSlowSource
And only on Console.WriteLine(c.b.a.val)
we will wait loadFromSlowSource
be done.
Is it possible in CLR/KRE?
@ggrnd0
async
code, because it negates any advantages of introducing asynchrony and because it very commonly leads to deadlocks.@svick,
1) auto add AsyncAttribute for method in compile time if it asynchronous or call any asynchronous method. Do not know what to do with condilional async method call...
2) everything leads to deadlocks, just current way too. There is error in async design, is not it?
There are two best practices (both covered in my intro post) that avoid this situation:
1. In your “library” async methods, use ConfigureAwait(false) wherever possible.
2. Don’t block on Tasks; use async all the way down.
1) it's too hard. i think there is simpler way exists.
ThreadStatic vs DeadLocks? I do not think what use ThreadStatic with async is good idea ever.
2) i prefer it. and it will be done automatically by compiler and clr.
The another problem what i see is how to stop async?
How clr must determine when async must be stoped? In mvc any async results if they used will acessed befire ActionResult.Execute end calling.
But what about void and unused results? How wait their?
Yes this feature is too hard and complex. But i think this problems can be resolved.
And more, i think clr can know better when async needed or not and can do it independently.
I do not want to write async Task
and await
every there. I am too lazy =)
I found another way
await
works like now, wait for executing async or not method.
but async Method()
call method asynchronously. And await or property access breaks asynchronous.
In critical places when u want to exsure method executed you use await
and do not otherwise.
if you want to start async executiong just write async
.
This is simple? i think...
And new code example:
calss A{string val;}
class B{A a;}
class C{B b;}
A loadA(){
return async loadFromSlowSource();
}
B getB(){
var b = new B{a=loadA()};
//some code in getB
return b;
}
C getC(){
var c = new C{b=getB()};
//some code in getC
return c;
}
void main(){
var = await getC();
//some code in main
Console.WriteLine(c.b.a.val);
}
When we call async loadFromSlowSource();
we create async task what works asynchronously untill we do not access any A instance fields or use await
on any top level method _calling ended_.
And if loadFromSlowSource work too long some code in getB
and some code in getC
will execute parallely with loadFromSlowSource
And only on await getC()
(or without await onConsole.WriteLine(c.b.a.val)
) we will wait loadFromSlowSource
be done.
@Ryancerium capture lists do not have anything to do with the parameters, so placing keywords in the parameters is not logical.
One thing that would be really useful when writing high performance C# are generic pointers. For the moment we have to duplicate by hand (or via T4) the implementation for each type.
class NativeArray<T> where T : unsafe struct
{
private readonly T* _ptr;
/* ... */
public T this[long index]
{
get { return *(_ptr + index); }
set { *(_ptr + index) = value; }
}
}
Yeah blittable would be a nice constraint but its not reasonable without some CLR reworking.
All so that you don't have to write async
and await
?
I would rather be explicit about when the code is going to execute in parallel.
Søren Palmund
Den 03/02/2015 kl. 17.41 skrev ggrnd0 [email protected]:
@svick,
1) auto add AsyncAttribute for method in compile time if it call
2) everything leads to deadlocks, just current way too. There is error in async design, is not it?There are two best practices (both covered in my intro post) that avoid this situation:
- In your “library” async methods, use ConfigureAwait(false) wherever possible.
- Don’t block on Tasks; use async all the way down.
1) it's too hard. i think there is simpler way exists.
ThreadStatic vs DeadLocks? I do not think what use ThreadStatic with async is good idea ever.2) i prefer it. and it will be done automatically by compiler and clr.
The another problem what i see is how to stop async?
How clr must determine when async must be stoped? In mvc any async results if they used will acessed befire ActionResult.Execute end calling.
But what about void and unused results? How wait their?Yes this feature is too hard and complex. But i think this problems can be resolved.
And more, i think clr can know better when async needed or not and can do it independently.
I do not want to write async Task and await every there. I am too lazy =)
I found another way
await works like now, wait for executing async or not method.
but async Method() call method asynchronously. And await or property access breaks asynchronous.In critical places when u want to exsure method executed you use await and do not otherwise.
if you want to start async executiong just write async.
This is simple? i think...And new code example:
calss A{string val;}
class B{A a;}
class C{B b;}A loadA(){
return async loadFromSlowSource();
}
B getB(){
var b = new B{a=loadA()};
//some code in getB
return b;
}
C getC(){
var c = new C{b=getB()};
//some code in getC
return c;
}
void main(){
var = await getC();
//some code in main
Console.WriteLine(c.b.a.val);
}
When we call async loadFromSlowSource(); we create async task what works asynchronously untill we do not access any A instance fields or use await on any top level method calling ended.And if loadFromSlowSource work too long some code in getB and some code in getC will execute parallely with loadFromSlowSource
And only on await getC() (or without await onConsole.WriteLine(c.b.a.val)) we will wait loadFromSlowSource be done.
—
Reply to this email directly or view it on GitHub.
@Miista, yes. I do not want to write async/await/Task everywhere.
First, you must migrate legacy code for asynchronous.
And second, you must allways write async/await/Task.
It is tediously....
If there any way to do it implicit it will. But if noone i am sad =)
But if you do it your way it isn't clear if the code will run asynchronously or not.
Søren Palmund
Den 03/02/2015 kl. 18.55 skrev ggrnd0 [email protected]:
@Miista, yes. I do not want to write async/await/Task anywhere.
First, you must migrate legacy code for asynchronous and you must allways write async/await/Task.
It is tediously....If there any way to do it implicit it will. But if noone i am sad =)
—
Reply to this email directly or view it on GitHub.
@Miista, yes...
But i think there are more chanses when it independent then not.
If you want ensure async just write async
.
If you want ensure value is materialized just write await
.
Write what you want to get or nothing if it independent.
So code will be asynchronous if it is inside used libraries and is not otherwise.
I do not want to know is implementation of IRepository{obect Get(id)} asynchronous or not.
I just want object as fast as it possible.
I do not want to rewrite hundreds of methods.
I do not know is it possible to do asynchronous implementation of method.
Of course there is crutch Task.FromResult()
, but it ugly too. it is redundant code....
And, for easement, async
and await
blocks for multiple method calls.
Like:
void method(){
async{
asyncTask1();
asyncTask2();
asyncTask3();
//asyncTask1, asyncTask2, asyncTask3 call asynchronously
}
//asyncTask1, asyncTask2, asyncTask3 still in asynchronously calling
await{
asyncTask4();
asyncTask5();
asyncTask6();
//asyncTask4, asyncTask5, asyncTask6 call asynchronously
}
//asyncTask4, asyncTask5, asyncTask6 ended
//asyncTask1, asyncTask2, asyncTask3 still in asynchronously calling
}
await method();
//asyncTask1, asyncTask2, asyncTask3 ended
People can make a mistake but machine must not.
I think what all of this (async await) is possible and just await for it =)
Note for https://github.com/dotnet/roslyn/issues/98#issuecomment-72332336
Another way is add information about method return type.
Write this:
var Method(){
return new {Name = "Alice", Age = 21};
}
CodeHint will be:
T Method() where T is {string Name, int Age}
So you can access properties of T:
var girl = Method();
Console.WriteLine($"{girl.Name} is {girl.Age} years old.");
Or something similar....
Code contacts can be:
and should have a way to specify then the contract is enforced.
Also is it possible to have the C# syntax as a library as in Racket so this can be imported and even modified and extended in certain scopes.
@sirinath See #129
Using generic types without specify Type-parameters
For interface IEnumerable<T>
compiler will identify IEnumerable
like IEnumerable<object>
Also, missed Type-params can be determine from execution context.
If compiler cannot determine count and/or type-params compiler will receive error message.
If it is too hard for compiler than another way:
Type aliases
We can create type aliases by using SConsole = System.Console;
now.
I offer for declaring aliases in code:
public alias IEnumerable = IEnumerable<object>;
Interface IEnumerable
will be showed in CodeHint and will be replaced for IEnumerable<object>
by compiler.
Interface default methods
Each default method will accessible like explicit implemented interface method.
There can be colisions when interface C
inherits multiple interfaces with same default methods.
I think they both must be ignored by compiler, and interface C
will not inherits default implementation.
Or more, interfaces will not inherit default implementations from parent interfaces.
But they will inherit signatures of default methods.
Extention methods do something similar, but requires namespace importing...
Don't you mean traits?
Søren Palmund
Den 08/02/2015 kl. 12.14 skrev ggrnd0 [email protected]:
Interface default methods.
Each default method will accessible like explicit implemented interface method.
There can be colisions when interface C inherits multiple interfaces with default methods.
I think they both must be ignored by compiler, and interface C will not inherits default implementation.Or more, interfaces will not inherit default implementations from parent interfaces.
But they will inherit signatures of default methods.For simple cases default interface methods can be powerfully then Extention methods becouse they do not require adding import of namespace.
—
Reply to this email directly or view it on GitHub.
I forgot for traits.
Traits is better than interface default methods.
catch
and finally
blocks after using
Make all types to be assembly neutral!!!
try {} fault {}
would be a small but nice addition.
It exists in MSIL and although C# doesn't expose it directly, it sometimes already generates it (e.g. inside iterators).
It's not something that is insanely useful but I have wished it existed a few times. It also makes C# more feature-complete with regard to try
blocks, now that it has gained exception filters.
current method pointer. for using nameof(thisMethod)
or doing reqursive calls thisMethod(params)
How nice it would use enumerators equal to JAVA 8.
I know this is closed, but box and unbox user-defined operators on value types would be nice.
Use case: Would allow user to control interning without having to call another method.
@leppie , is it https://msdn.microsoft.com/en-us/library/aa288476(v=vs.71).aspx ?
@ggrnd0: I guess it could/would be implemented using the same syntax (I would prefer it being more explicit), but currently you cannot implement user-defined conversions to and from object
. It is not allowed.
@leppie , i forgot it... there would be an exclusion for value types. +1 for it.
Another small and strange thing:
Make System.Int32 same like int: you cannot use System.Int32 for enum
.
But it does not mater if enum
will be reference type like java.
@ggrnd0 You can use System.Int32 for an enum base type in C# 6.
+
Rather than NonNull
What is Default
Well, I'm glad you asked. Defaultvar a = b!
is semantically identical to b.Value = b.Value ?? b.Default; var a = b.Value
. Thus the only caveat is that wherever a variable or field of type Default
The power of Default, though, over any other approach, is the freedom it gives the programmer in deciding that default value. In a single function, you could declare three string!
s, one with a default value of "true", one with "false", and one with "FILE_NOT_FOUND".
To create that initial T!, we have a static helper method Default.Create, much like Tuple.Create, that provides several options: T! Default.Create(T t)
, which must be statically checked to only take an immediately constructed value or a string constant (trivially: Default.Create(new T())
passes, all else fail), T! Default.Create<T>() where T : new()
or, T! Default.Create<T>(Func<T!> factory)
.
Methods can then annotate their input parameters with T! for free. Values of type T can be returned or assigned to out parameters of type T! if and only if that variable is definitely assigned AND is never assigned a nullable value (except from the left side of ??
). The compiler then auto-wraps that value into a Default
Objects can not be instantiated with Defaultb.Value = b.Value ?? b.Default; var a = b.Value
sugar to still work flawlessly even when b came from a generic container. Unfortunately, Default
Further sugar could allow class authors to specify a no-arg constructor as default (suggested syntax: C() : default { }
; string(char c = '\0', int n = 0) : default
, etc.) allowing T! of that type to be instantiated without going through the Default
class' helpers.
One last concern is what happens if someone decides to throw new NullReferenceException()
inside a constructor or IDefault
In closing, the advantages of this scheme are:
Since you're discussing C# design, can you please look into an IAbortDisposable
or somesuch that the compiler can pick up and clean up? To my knowledge this is a problem that has been going on since WCF premiered, where WCF clients can be in an open state or in a faulted state.
Perhaps a WCF client proxy could implement IAbortDisposable or IDisposeAbortable or something, and the syntax sugar to make use of it might be something like ...
using (var proxy = new MyServiceProxy()) {
// do stuff, and then always automatically .Dispose() or .Abort()
} finally {
if (proxy.IsFaulted) {
// do cleanup before the CLR automatically invokes .Abort()
}
}
This way .Dispose() always works but if it's faulted then there is an opportunity to clean up or something. I'm just brainstorming syntax ideas, but to manually do the following instead of using(..) {}
..
if (this.State == CommunicationState.Closing ||
this.State == CommunicationState.Closed ||
this.State == CommunicationState.Faulted)
{
this.Abort();
}
else
{
this.Close();
}
.. is a nightmare.
@stimpy77 To me, that sounds as if WCF should be fixed, instead of creating a language feature to fix it from the outside.
And, how is your IAbortDisposable
any better than normal IDisposable
, whose implementation of Dispose()
looks something like the following?
c#
if (this.IsFaulted)
this.Abort();
else
this.Close();
@stimpy77, I agree with @svick. The fact that WCF is so complex that it doesn't work with using (...) {}
is not the problem of the C# language, it's the problem of WCF and should be fixed in WCF.
Code contracts would be an improvement, but they treat the symptom, not the disease, as it were.
Say your method only accepts whole numbers, but uses an int
parameter, which can theoretically be negative. Sure, putting a contract on the parameter to ensure it is >= 0 provides some protection, but it just moves the problem, so now the callee either has to do the same checks or defaulting before calling the method, or it has to handle the exceptions.
In the end, code contracts don't address the underlying issue -- _your parameter has the wrong logical type_. You're using int
when you really want a far more limited type of either _zero or a positive integer_. Using an unsigned integer would be better, but has its own foibles, so we hold our nose and pretend that a signed type for a never-negative parameter is our best option.
So what's really going on is that your code contract is creating, logically, an anonymous type with restrictions not present in the base type. But by making it anonymous, it's not reusable, either between methods _or between the method and the caller_.
A better approach, IMHO, is to use the type system. E.g., if I want only whole numbers, I create a type that aliases int but does not allow negative numbers to be assigned to it:
public contract WholeInt : int where >= 0;
public contract PositiveInt : int where >= 1 ?? 1;
public contract NNString : string where !null ?? String.Empty;
public class Customer {
public WholeInt Age { get; set; }
public NNString Name { get; set; }
public PositiveInt NumVisits { get; set; }
}
This moves the responsibility back where it belongs: where the invalid value assignment occurs, not when some hapless method gets the bad value as an argument. It also encourages reuse, and provides the option of an _alternative default_ rather than an exception when a bad value is assigned or the default value of the underlying type would be invalid.
For backward compatibility, it should always be possible to implicitly cast one of these contract types to their underlying type. This would allow, for example, ICollection<T>.Count
to return a WholeInt
but callers can still assign the result directly to Int32.
Using the keyword contract
above is just an example -- perhaps extending the concept of an Interface would be better.
@richardtallent you make some very good points which should be taken note of. I guess the anti-pattern you've sniffed out there is a flavour of PrimitiveObsession.
Brilliant ideas, @richardtallent! I'd love to see something like that in C# one day.
Of course, we do already have a type system which allows us to encapsulate such things :wink:
The 'contracts' demonstrated above are a shorthand for value types. Whilst the syntactic sugar may drastically reduce LOC, and I welcome such improvements, we shouldn't shy away from practising this encapsulation today just because the convenient shorthand doesn't yet exist.
We should also take care not to travel only the half the distance away from anti-patterns like primitive obsession:
public contract Age: int where >= 0;
public class Customer
{
public Age Age { get; set; }
}
Adam, you're right, it is a form of PrimitiveObsession. I use structs to resolve this in my own code and it works brilliantly, but syntactic sugar around to accomplish the same thing more expressively would be a welcome change.
I agree about not "traveling half the distance," but I think there should be room for allowing contracts to be composed:
public contract WholeInt : int where >= 0;
public contract PositiveInt : WholeInt where != 0;
public contract CustomerVisitCount : PositiveInt;
This is straightforward (but terribly wordy) to do with existing structs, and it's more DRY-friendly, since the same value constraints tend to pop up regularly.
I toyed around in my head the possibility of polymorphic contracts (e.g., contract PositiveInt : WholeInt, NotZeroInt
) to allow even more flexible reuse, but I think I've convinced myself it would not be sufficiently better than strict composition to be worth the effort.
If Microsoft does grant us something like this, it would be great if they updated various BCL methods to use these more restrictive value types. For example, List<T>.Item
could take WholeInt32 rather than plain old Int32. Maybe that would cause compatibility issues, even with implicit conversion to and from Int32. Still, it would be nice to move that direction.
I strongly prefer for let
instead of readonly
or val
for readonly primitives (and types).
It is used in F#, so using let
would be more consistent between different languages.
The idea of @richardtallent to define types might be a good idea. Howeven, contracts are also used ro ensure pre- and postconditions and not just type checking. So it might only be considered additionally.
Why don't we have a method returning var
(meaning auto
)? because its not a variable?
We also have let
for declarations inside linq queries.
What keyword would a method return for specifing auto
?
I think this is becoming a mess.
Support for something like this?
class Test {
string attribute { get; }
public Test(int input, string test) {
int value = input + 1; // static context.
base(value);
attribute = test;
}
}
For implementing pattern matching, I do not like to use a switch
statement, since it does not return a value:
int result = match animal {
case is Dog: 1;
case is Cat: 2;
default: 0;
}
@jvlppm it would be almost pointless to have a method that returns var
.
Granted, the return type could be interfered by the compiler, which would ease refactorings. but it might also increase the programmer error rate by beeing less explicit.
I believe it is very important to have a language that decreases the potential error rate by design, which is why non-nullable reference types, readonly values, contracts, pattern matching, and even units/dimensions are a good idea.
@ggrnd0 the catch
/finally
block after a using
block is not a very good idea, since having both in the same method violates SRP. Using an aspect to do the exception handling is a much better idea.
Method Contracts should be generalized out to a traits system ( #129 ).
@AdamSpeight2008 I agree that traits are a powerful concept.
However, I am unsure if that can do things like checking the order in which methods are called at compile time, as you can do with contracts.
@richardtallent i would use the value
keyword in your example:
public contract WholeInt : int where value >= 0;
public contract PositiveInt : int where value >= 1;
public contract NonEmptyString : string where value != null && value != String.Empty;
On Apr 24, 2015, at 12:02 AM, Johann Dirry [email protected] wrote:
@richardtallent i would use the value keyword in your example:
public contract WholeInt : int where value >= 0;
public contract PositiveInt : int where value >= 1;
public contract NonEmptyString : string where value != null && value != String.Empty;
Excellent idea. It also makes it easier to support conditions that need dotted notation, like the following:
public contract QuadrantIPoint : Point where value.X >=0 && value.Y >= 0;
public contract SSN : string where (value != null) && (value.Length==9) && value.All(c => c >= '0' && c <= '9');
Regarding your comment earlier about pre/post conditions, I agree. This concept would handle many common pre/post conditions, but since the contract is defined outside the method taking or returning it, it would have limited visibility and would not be able to, for example, compare its value to other arguments of the method. So it's not a complete replacement for the functionality of the current contract system, just a way to cleanly deal with classes of contracts that really just boil down to a more constrained version of another type.
--Richard
Abstraction over generics, anyone +1?
I mean, I can abstract over types with generics, e.g. List<T>
, but for some reason I cannot abstract one level above e.g. MyKind<F<_>>
where MyKind
takes not a proper type, but a generic as a parameter which you would construct like, say, MyKind<List>
or MyKind<Task>
This would be very and opens soooo many doors (in functional programming direction mainly, but not only). For example, it would finally be possible to generalise over IEnumerable<T>
and IObservable<T>
and to have functionality that can accept either of them.
Or it gives us the ability to write functions that preserve shape, like "you give me a list - I return you a list, you give me a task - I return you a task, you give me an observable - I return you an observable".
Sum types!
Someone has mentioned discriminated unions, from my POV it is much bigger than any contracts, especially if we have pattern matching.
Apologize if I'm writing to the wrong thread, please direct me if I should post the idea somewhere else or open separate issue for that.
From my experience I noticed same typical situation that I write over and over:
``` c#
foreach (var languageVersions in languageData)
{
var language = languageVersions.Key;
var versions = languageVersions.Value;
foreach (var versionFields in versions)
{
var versionNumber = versionFields.Key;
var fields = versionFields.Value;
Process(language, versionNumber, fields);
}
}
It would be really handy if there is special support of IDictionary<TKey, TValue> in C# that can simplify the code and make it more expressive. Something like that:
``` c#
foreach (var language, versions in languageData)
{
foreach (var versionNumber, fields in versions)
{
Process(language, versionNumber, fields);
}
}
Does anybody think it is a good idea?
@AlenPelin if KeyValuePair<,>
could be treated as a tuple, since Dictionary<,>
implements IEnumerable<>
you should get this out-of-the-box.
foreach ((var language, var versions) in languageData)
{
foreach ((var versionNumber, var fields) in versions)
{
Process(language, versionNumber, fields);
}
}
@alrz thanks, I will check that.
UPD: I reviewed the tuple concept and you seem to be right, just need to wait for tuples to be implemented first ^_^ which is quite complicated thought.
@alrz The foreach
loop does not specify that it does decomposition, so even if we add a decomposition operator/assignment to the language, you would not get any special support in foreach
without additional language support. Specifically, the syntax you wrote provided a type for the iteration variable (var language, var versions)
but then you omitted the name of the variable - thus it would be a syntax error.
Thanks @gafter for your comments.
Well, as soon as foreach
needs special support for either KeyValuePair
, or tuples
and KeyValuePair
needs tuple representation, I believe first option is much easier to implement. Anyway, the question is still open: whether we really need that sugar or not.
@gafter of course currently it is a syntax error! this is based on my assumption — that pattern matching, tuples, record types, etc are a group of features (in a functional language though) that always come together, otherwise it doesn't make much sense. If we have special syntax for them it should support decomposition everywhere not just in assignments. including
// switch statement
void F(object o) {
switch(o) {
case (int item1, int item2): ...
}
}
// method parameters
void F((int item1, int item2)) { ... }
and aforementioned scenarios — which are supported in F# plus a powerful type inference, you don't even need to mention types as I did here.
and I didn't quite get what you meant by
you omitted the name of the variable
of course I did because I'm not intrested in the tuple itself, but just the members. However, in Haskell you can have both at the same time with as-patterns e.g. whole_tuple@(item1,item2)
hence it wouldn't be an unreasonable feature.
@alrz We already have one set of method overload resolution/dispatch rules. It is too late to replace them with a set that would have made sense if we had started with pattern matching. For example, if we were to do pattern matching for method dispatch as many functional languages do, we would select the overload based on the dynamic type of parameters rather than just upon the static type. Since that would change the behavior of existing code (int x
is syntactically a pattern and also a parameter declaration), we cannot compatibly make that change.
Design notes have been archived at https://github.com/dotnet/roslyn/blob/future/docs/designNotes/2015-01-21%20C%23%20Design%20Meeting.md but discussion can continue here.
Most helpful comment
+1 to the Contracts system. There's already a similar concept with type constraints for generics.
An extension to this pattern for functions would be intuitive to anyone familiar with constraints.
Would separate 'ensures' and 'requires' actually be necessary? Could the statement be inferred?