Skip to content

Instantly share code, notes, and snippets.

@controlflow
Last active August 29, 2015 13:58
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save controlflow/9996665 to your computer and use it in GitHub Desktop.
Save controlflow/9996665 to your computer and use it in GitHub Desktop.
Possible C# primary constructors design
class Person : EntityBase {
// ~familiar syntax, no problems with xml doc, can omit body, can omit public?
public constructor(int id, string name, int age) : base(id);
readonly string _mrName = "Mr. " + name;
public string Name { get; } = name;
public int Age { get; } = age;
}
class Person {
// can change visiblity and add body for checks
private constructor(string name, int age) {
if (name == null) throw new ArgumentNullException("name");
}
public Person() : this("Foo", 42) {
// secondary
}
public string Name { get; } = name;
public int Age { get; } = age;
}
class Component {
// explicit capture, can omit private when readonly
[ImportingConstructor] // no problems with attributes
public constructor([NotNull] readonly IFoo foo, [NotNull] readonly IBar bar);
public IFoo ExposedFoo => foo;
public void M(foo) {
// capture declares ordinary fields from class parameters,
// so conflicts with locals can be resolved by 'this.' qualifier
... this.foo ...
... bar ...
...
}
}
// placing primary constructor inside class body prevents from ability to put tons of code
// outside of class declaration body block, keeping class name and extends clause clear.
// I'm expecting silly classes like this:
class Component(IFoo dependency, IBar other, IBlah anotherOne)
: MySuperBaseType(dependency, other, anotherOne, (HowPeopleLove to) => {
put.LambdaExpressions(Inside.Base.Initializer);
InsteadOfOverridingMethods();
HowIHateThis();
}), ISomeInterface, IOtherInterface
{
}
@ashmind
Copy link

ashmind commented Apr 6, 2014

Attribute specifier "constructor:" exists in C#
Are you sure? C# 5 spec lists the following:

global-attribute-target:
  assembly
  module

attribute-target:
  field
  event
  method
  param
  property
  return
  type

Provide you with examples of shitty code because you don't 'seen it at all'? Maybe you can just believe me, because I've already kill code like this in our code base?

Maybe it is specific to your codebase though, people just learning incorrectly from existing code. I do not disbelieve this exists, I am just trying to understand why anyone would use it.

It is hard to provide syntax for explicit body to do side-effects like argument checks and event subscriptions;
It is not that hard (just stuff the {} somewhere), but I would argue it is unnecessary for the primary constructor. You can always fall back to using normal constructor if you have complex logic. And argument checks can be easily provided btw:

 public string X { get; } = Argument.NotNull(x);
 // or even (shittier)
 public string X { get; } = (
     Argument.RequireNotNull(x);
     x;
 ); // if I understand ; operator correctly

XML documentation is the issue, you will unable to write famous useless summary like "Initializes the new instance of StringBuilder class";
As I said, and you say, this is useless, and especially useless for primary constructor.

It is hard to find a place for visibility modifier;
I agree, but I do not see a problem with limiting these to public (protected for abstract) as that would be most common use case. You can always just write a normal constructor if you want more control.

Class declaration upper side to looks messy - sometimes you will not be able to easily find base type specification or interface implementation;

This is subjective, I do not find your third example hard-to-read.

However, I do find this weird:

class Person {
  public string Name { get; } = name;
  // ...
  // ...
  // ...
  constructor(string name) { }
}

@ashmind
Copy link

ashmind commented Apr 6, 2014

In general I see primary constructors as something similar to autoproperties -- they are not a silver bullet for everything.
If you need something uncommon such as private constructor or event subscription in constructor, you can fall back to using normal constructor. Though if second part is common, it can be done by allowing a code block one way or another. I am just not sure it is common.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment