This project is read-only.

Primary constructors syntax

Topics: C# Language Design
Apr 7, 2014 at 7:23 AM
Edited Apr 7, 2014 at 7:37 AM
Hi C# team.

C# 6.0 has become something new to me. Some of the new features make interest for me, and some of them - not. Let's have a little talk on the syntax of primary constructors. The primary constructors syntax seems to pollute "classic" class declaration, and probably repeats a thing happened to Java generic class declaration syntax. For example, suppose you have a generic class parameterized with two types T and U respectively. This is how it's written in Java:
class FooClass<T extends Interface1, U extends Interface2> extends BarClass<T, U> implements Interface0 
Let's rewrite the above code using C#
class FooClass<T, U> : BarClass<T, U>, Interface0
    where T : Interface1, U : Interface2
I guess you'd all agree that C# type restrictions syntax order is cleaner where the class declaration and type restrictions are separated. Let's take a C# 6.0 primary constructors example from Jon Skeet's blog page:
internal struct Transition(Instant instant, private Offset oldOffset, Offset newOffset) : IEquatable<Transition> 
{ 
    public Instant Instant { get; } = instant; 
    public Offset NewOffset { get; } = newOffset; 

    // Methods 
}
What would you think if the code above could be rewritten using another syntax in manner of:
internal struct Transition : IEquatable<Transition> 
    : new(Instant instant, private Offset oldOffset, Offset newOffset)
{ 
    public Instant Instant { get; } = instant; 
    public Offset NewOffset { get; } = newOffset; 

    // Methods 
}
?

Thanks in advance.
Apr 7, 2014 at 10:47 AM
You then would also have to Change how you call base Constructors, for what i know right now it is like so:
class DefinitiveBase(string x) 
{
    public string X { get; } = x;
}

class Definitive(string a, string x) : DefinitiveBase(x)
{
   public string A {get; } = a;
}
with your Syntax that must be different, i guess this would be how it could be done then:
class Definitive : DefinitiveBase 
  : new(string a, string x) 
  : base(x)
{
   public string A {get; } = a;
}
This would stil be a nice Syntax depending on where you place the "where" Syntax, but this could get messy in combination with "partial".
Apr 7, 2014 at 1:53 PM
@Flowster
thank you for your reply. Could you please explain what you mean saying "messing in combination with partial"?
Apr 7, 2014 at 2:19 PM
Edited Apr 8, 2014 at 3:15 PM
That's an interesting idea and a very valid observation, halogen. Especially since I think that primary constructors require bodies for argument validation, etc. (see also https://roslyn.codeplex.com/discussions/540281). So we might end up with something like this:
public class Texture2D
   : new(private GraphicsDevice device, private Size size)
   {
       Debug.Assert(device != null);
       Debug.Assert(size < GraphicsDevice.MaxTextureSize);

       // Create texture using Direct3D or OpenGL
   }
{
    // Other members
}
Update: The proposed syntax would also allow to specify the accessibility of the primary constructor like so: public class Texuture2D : internal new (...). The more I think of that, the more I like that.
Apr 8, 2014 at 12:12 AM
The primary constructors notion sounds somewhat like a concept I'd been wishing for, which would be a means of tagging members to indicate that their initial value should be set by a like-named constructor parameter; all constructors of a class containing any such members would be required to either have parameters of corresponding names and types, or else chain to one which did. The members could either be declared as ephemeral (would not generate fields), or as mutable or immutable fields or properties of any desired scope. Ephemeral or immutable members could be used within other initialization expressions.

Such a design would avoid the need to change other aspects of constructor syntax, while still allowing initialization expressions that depend upon constructor parameters to be evaluated before the base object is constructed.
Apr 8, 2014 at 1:01 PM
Edited Apr 8, 2014 at 1:06 PM
@Expandable
if I understand you correctly, this could also allow to have multiple primary constructors with trivial overloads. Frankly speaking, I'm not a big fan of constructor bodies outside their class body itself, also preferring factory methods with checks and assertions in favor of constructors. From my point of view, a class should have one (probably private) constructor only without any checks or assertions inside, just assigning the constructor arguments to the new instance fields, so all necessary contract checks and data transformation could be done in factory methods. For me it looks very similar to what current primary constructors can do, but in another syntax that I find noisy.
Apr 8, 2014 at 1:31 PM
Edited Apr 8, 2014 at 1:31 PM
I'm not sure I'd allow multiple primary constructors - they wouldn't really be "primary" then. From a syntax point of view, that would be totally possible, however.

I personally have a strong distaste for factory methods. They are sometimes necessary and in some rare cases (especially for structs or in conjunction with generic arguments) nicer, but whenever a regular constructor could achieve the same thing, I use a regular constructor. That's what they're there for and it makes for a much nicer API, in my opinion.
Apr 8, 2014 at 1:53 PM
No. There's only one primary constructor.
Apr 8, 2014 at 5:26 PM
I’ve summarized an alternative proposal here:

https://roslyn.codeplex.com/discussions/541575

In this idea, I describe an idea that works quite differently from the existing “primary constructor” idea, but I think it works better to solve the use-cases it is trying to address.
Apr 12, 2014 at 8:12 PM
@PauloMorgado
thanks, I wasn't aware of that. And this is a rule that I really like.

@everyone
Since the talk here is only about the primary constructor syntax, not the feature itself, what would you think if the number of parameters in the primary constuctors is too big? Would you agree that readability suffers in such a scenario?