C
C#15mo ago
joren

❔ Defining base impl ctor in interface

So currently for some testing I have the following code:
interface HumanInterface
{
public string Name { get; }
public string Description { get; }

public void walk() { Console.WriteLine("Default implementation"); }

// Forcing implementing class to define scream()
public void scream();
}

class Foo : HumanInterface
{
Foo(string name, string description)
{
Name = name;
Description = description;
}

public string Name { get; }
public string Description { get; }
void HumanInterface.scream() { Console.WriteLine("Screams"); }
}
interface HumanInterface
{
public string Name { get; }
public string Description { get; }

public void walk() { Console.WriteLine("Default implementation"); }

// Forcing implementing class to define scream()
public void scream();
}

class Foo : HumanInterface
{
Foo(string name, string description)
{
Name = name;
Description = description;
}

public string Name { get; }
public string Description { get; }
void HumanInterface.scream() { Console.WriteLine("Screams"); }
}
my ctor Foo is pretty generic, in fact I'd probably want all my derived classes to have that exact ctor. How'd I achieve this?
91 Replies
joren
jorenOP15mo ago
interface HumanInterface
{
public string Name { get; init; }
public string Description { get; init; }

public void walk() { Console.WriteLine("Default implementation"); }

// Forcing implementing class to define scream()
public void scream();
}

class Foo : HumanInterface
{

public string Name { get; init; }
public string Description { get; init; }
void HumanInterface.scream() { Console.WriteLine("Screams"); }
}
interface HumanInterface
{
public string Name { get; init; }
public string Description { get; init; }

public void walk() { Console.WriteLine("Default implementation"); }

// Forcing implementing class to define scream()
public void scream();
}

class Foo : HumanInterface
{

public string Name { get; init; }
public string Description { get; init; }
void HumanInterface.scream() { Console.WriteLine("Screams"); }
}
Foo a = new Foo { Name = "John", Description = "A person" };
Angius
Angius15mo ago
You can use the : base()
class Bar : Foo
{
public Bar(string name, string desc) : base(name, desc) {}
}
class Bar : Foo
{
public Bar(string name, string desc) : base(name, desc) {}
}
Or an abstract class ig
joren
jorenOP15mo ago
abstract class is the same as in C++ I assume? at least one pure virtual method and its abstract?
Angius
Angius15mo ago
There's abstract modifier You can have an empty abstract class just as well
joren
jorenOP15mo ago
ah right
MODiX
MODiX15mo ago
Angius
REPL Result: Failure
abstract class Foo {}
new Foo();
abstract class Foo {}
new Foo();
Exception: CompilationErrorException
- Cannot create an instance of the abstract type or interface 'Foo'
- Cannot create an instance of the abstract type or interface 'Foo'
Compile: 454.425ms | Execution: 0.000ms | React with ❌ to remove this embed.
joren
jorenOP15mo ago
mhm fair enough do ppl even use the interface keyword often seems terribly limited honestly
Angius
Angius15mo ago
Yes, interfaces are very common C# has no multiple inheritance But a class can implement many interfaces
joren
jorenOP15mo ago
unless its an interface no? yy eh, that blows, what about my init; approach, would that be a acceptable approach? or do people avoid this altogether
Angius
Angius15mo ago
Yeah, initializer syntax is commonly used And yeah, you can use required
joren
jorenOP15mo ago
required as in? there's a keyword?
Angius
Angius15mo ago
class Foo
{
public required int Thing { get; set; }
}
class Foo
{
public required int Thing { get; set; }
}
joren
jorenOP15mo ago
ah so we force them to set it since i have a non-nullable type its actually pretty relevant
MODiX
MODiX15mo ago
Angius
REPL Result: Failure
class Foo
{
public required int Thing { get; set; }
}
new Foo()
class Foo
{
public required int Thing { get; set; }
}
new Foo()
Exception: CompilationErrorException
- Required member 'Foo.Thing' must be set in the object initializer or attribute constructor.
- Required member 'Foo.Thing' must be set in the object initializer or attribute constructor.
Compile: 478.418ms | Execution: 0.000ms | React with ❌ to remove this embed.
MODiX
MODiX15mo ago
Angius
REPL Result: Success
class Foo
{
public required int Thing { get; set; }
}
new Foo { Thing = 420 }
class Foo
{
public required int Thing { get; set; }
}
new Foo { Thing = 420 }
Result: Foo
{
"thing": 420
}
{
"thing": 420
}
Compile: 522.218ms | Execution: 62.802ms | React with ❌ to remove this embed.
joren
jorenOP15mo ago
required does not work within an interface it facepalm there goes my plan
interface HumanInterface
{
public string Name { get; init; }
public string Description { get; init; }

public void walk() { Console.WriteLine("Default implementation"); }

public void scream();
}

class Foo : HumanInterface
{
public required string Name { get; init; }
public required string Description { get; init; }
void HumanInterface.scream() { Console.WriteLine("Screams"); }
}
interface HumanInterface
{
public string Name { get; init; }
public string Description { get; init; }

public void walk() { Console.WriteLine("Default implementation"); }

public void scream();
}

class Foo : HumanInterface
{
public required string Name { get; init; }
public required string Description { get; init; }
void HumanInterface.scream() { Console.WriteLine("Screams"); }
}
you know what bothers me, the fact that this has so much duplicate code, specifically the members are a bother to me
public string Name { get; init; }
public string Description { get; init; }
public string Name { get; init; }
public string Description { get; init; }
so what exactly is this, member declaration with definitions (much like setters/getters)?
Angius
Angius15mo ago
$getsetdevolve
MODiX
MODiX15mo ago
class Foo
{
private int _bar;

public int GetBar()
{
return _bar;
}

public void SetBar(int bar)
{
_bar = bar;
}
}
class Foo
{
private int _bar;

public int GetBar()
{
return _bar;
}

public void SetBar(int bar)
{
_bar = bar;
}
}
can be shortened to
class Foo
{
private int _bar;

public int GetBar() => _bar;

public void SetBar(int bar) => _bar = bar;
}
class Foo
{
private int _bar;

public int GetBar() => _bar;

public void SetBar(int bar) => _bar = bar;
}
can be shortened to
class Foo
{
private int _bar;
public int Bar {
get { return _bar; }
set { _bar = value; }
}
}
class Foo
{
private int _bar;
public int Bar {
get { return _bar; }
set { _bar = value; }
}
}
can be shortened to
class Foo
{
private int _bar;
public int Bar {
get => _bar;
set => _bar = value;
}
}
class Foo
{
private int _bar;
public int Bar {
get => _bar;
set => _bar = value;
}
}
can be shortened to
class Foo
{
public int Bar { get; set; }
}
class Foo
{
public int Bar { get; set; }
}
joren
jorenOP15mo ago
though, in practice the get; and set; are much like changing the visiblity, rather than utilizing a setter/getter
Angius
Angius15mo ago
They're literally getter and setter See above
joren
jorenOP15mo ago
ye with some magic bcs when you are actually setting the value its literally obj.val = 34; not obj.SetVal(34), I dont really see the whole setter/getter back in practice
Angius
Angius15mo ago
Well, yes, with some magic We ain't writing Java, we don't write useless code lol
joren
jorenOP15mo ago
its literally just like a accessibility modifier in C++ you'd mark it public and call it a day because thats essentially what it is
Angius
Angius15mo ago
It's about encapsulation You expose the internal state of the object via this proxy
joren
jorenOP15mo ago
I assume it has no additional checks for set;?
Angius
Angius15mo ago
Well, it can if you want You can have { private set; protected get; } if you want Or you can implement some checks in the setter or getter
joren
jorenOP15mo ago
class A
{
public:
A(const int a) : a(a) {}
int a;
private:
...
};

A a(23);
a.a;
class A
{
public:
A(const int a) : a(a) {}
int a;
private:
...
};

A a(23);
a.a;
what's the difference? Pratically none
Angius
Angius15mo ago
Yeah, you're exposing the internal state directly
joren
jorenOP15mo ago
so it get; no? only difference is that you cannot set;, its split up and one protects the other from happening
Angius
Angius15mo ago
And if you wanted to not have the ability to set it, or not have the ability to get it, or return 0 if the member is < 0 you will have to break the contract by introducing getter/setter methods Not the case with C#
joren
jorenOP15mo ago
Fair guess it has some use, a fany accesibility modifier I'll call it protected doing what in this context is it so only the derived can use the get; i assume that actually, on second thought
Angius
Angius15mo ago
private makes the setter accessible only in this class, while protected makes the getter accessible in this class and all derived classes
joren
jorenOP15mo ago
its private by default I assume
Angius
Angius15mo ago
It's whatever the property is, by default
public int Foo { get; private set; } // get is public
public int Foo { get; private set; } // get is public
joren
jorenOP15mo ago
which is private unless you make it public? y
interface HumanInterface
{
// Cannot use required here...
public required string Name { get; init; }
public required string Description { get; init; }

public void walk() { Console.WriteLine("Default implementation"); }

public void scream();
}

class Foo : HumanInterface
{


void HumanInterface.scream() { Console.WriteLine("Screams"); }
}
interface HumanInterface
{
// Cannot use required here...
public required string Name { get; init; }
public required string Description { get; init; }

public void walk() { Console.WriteLine("Default implementation"); }

public void scream();
}

class Foo : HumanInterface
{


void HumanInterface.scream() { Console.WriteLine("Screams"); }
}
you see, this is what i'd want however this wouldnt work, but it got rid of the dumb double declarations of the Name and Description, how'd you write this?
Angius
Angius15mo ago
I'd honestly just use an abstract class instead
joren
jorenOP15mo ago
Guess I will have to start making more proper distinctions between interfaces and abstract classes in my decision making lol oh well, not the worst, safe to say im not a fan of interfaces in C#.
Angius
Angius15mo ago
Interfaces are best treated as literally just a contract
joren
jorenOP15mo ago
Yeah, they're very limited sadly guess Ill have to respect their use case more and stop trying to reinvent their use-case @angius So having members (or fields whatever they're called), is typicall not something you'd see back very often in an interface they're purely just: methods one has to implement in its child classes, maybe some default methods that can be overrided if wanted) and thats it
Angius
Angius15mo ago
Fields are an implementation detail, as they're usually private Properties and methods you would absolutely see in an interface
joren
jorenOP15mo ago
properties that have to be re-declared a tenfold? might as well omit them in the interface no? I suppose they enforce you to define them in the child classes
Angius
Angius15mo ago
Well... anything an interface declares has to be redeclared in the class that implements it
joren
jorenOP15mo ago
but its duplicate code disgusting, might as well opt for a abstract class instantly?
Angius
Angius15mo ago
Unless you use the default implementation, which is probably one of the biggest mistakes C# did lol
joren
jorenOP15mo ago
why's that, whats the tea here
Angius
Angius15mo ago
An interface should be just that, a contract It should contain no implementation detail Implementation is up to the class
joren
jorenOP15mo ago
fair actually considering they have abstract class too
Angius
Angius15mo ago
Default implementation was added so it's easier to refactor code, you can throw a NotImplementedException for example But people abuse it for more that that
joren
jorenOP15mo ago
// Define an interface for entities that can make a sound. It's basically a contract the child classes have to implement.
interface ISoundMaker
{
// You can define a default impl, but its frowned upon.
// Cannot define ctor's, so dont.

// Telling child class, this property has to be defined.
public string Name { get; }

// Has to be implemented
void MakeSound();
}

// Implement the interface in a class.
class Dog : ISoundMaker
{
public string Name { get; init; }

public void MakeSound()
{
Console.WriteLine("Dog barks.");
}
}

class Cat : ISoundMaker
{
public string Name { get; init; }

public void MakeSound()
{
Console.WriteLine("Cat meows.");
}
}

internal class Program
{
static void Main()
{
ISoundMaker dog = new Dog() { Name="Doggo" };
ISoundMaker cat = new Cat() { Name = "Catto" };

dog.MakeSound(); // Output: Dog barks.
cat.MakeSound(); // Output: Cat meows.
}
}
// Define an interface for entities that can make a sound. It's basically a contract the child classes have to implement.
interface ISoundMaker
{
// You can define a default impl, but its frowned upon.
// Cannot define ctor's, so dont.

// Telling child class, this property has to be defined.
public string Name { get; }

// Has to be implemented
void MakeSound();
}

// Implement the interface in a class.
class Dog : ISoundMaker
{
public string Name { get; init; }

public void MakeSound()
{
Console.WriteLine("Dog barks.");
}
}

class Cat : ISoundMaker
{
public string Name { get; init; }

public void MakeSound()
{
Console.WriteLine("Cat meows.");
}
}

internal class Program
{
static void Main()
{
ISoundMaker dog = new Dog() { Name="Doggo" };
ISoundMaker cat = new Cat() { Name = "Catto" };

dog.MakeSound(); // Output: Dog barks.
cat.MakeSound(); // Output: Cat meows.
}
}
any other important details im missing I assume thats all, pretty straight forward since its so limited yet simple. I suppose this'd be a proper use-case, my example. I assume dtor's are also not possible in the interface, right?
Angius
Angius15mo ago
LGTM
joren
jorenOP15mo ago
Just to be sure, this whole interface contract goes as deep as the compiler right? There's no case of vtables being generated, polymorpish, etc?
Angius
Angius15mo ago
And no, I don't think deconstructors (or do you mean destructors – finalizers?) are possible in an interface
joren
jorenOP15mo ago
you can create instance of ISoundMaker interface as I tested, this makes me suspect there's smth going on destructors, and I cant I just tested! Apologies I forget to share my finding.
Angius
Angius15mo ago
Not sure about the deep workings, but you cannot instantiate interfaces
MODiX
MODiX15mo ago
Angius
REPL Result: Failure
interface IFoo {}
var f = new IFoo();
interface IFoo {}
var f = new IFoo();
Exception: CompilationErrorException
- Cannot create an instance of the abstract type or interface 'IFoo'
- Cannot create an instance of the abstract type or interface 'IFoo'
Compile: 448.304ms | Execution: 0.000ms | React with ❌ to remove this embed.
joren
jorenOP15mo ago
No, just save its child classes inside it whats the command? to compile ;compile
interface IFoo {}
var f = new IFoo();
interface IFoo {}
var f = new IFoo();
Angius
Angius15mo ago
!e
MODiX
MODiX15mo ago
joren
REPL Result: Success
interface IFoo {}
class A : IFoo{}
IFoo f = new A();
interface IFoo {}
class A : IFoo{}
IFoo f = new A();
Compile: 472.861ms | Execution: 57.902ms | React with ❌ to remove this embed.
joren
jorenOP15mo ago
ye , and then when you'd call a method on f, it'll call the respective method of the underlying type thats polyphism concepts applied without vtables, virtual methods?
Angius
Angius15mo ago
Well, you're not creating ain instance of an IFoo
joren
jorenOP15mo ago
yes
Angius
Angius15mo ago
It's still an A
joren
jorenOP15mo ago
so it just treats it as A, but allows it to be represented by IFoo?
MODiX
MODiX15mo ago
Angius
REPL Result: Success
interface IFoo {}
class A : IFoo{}
IFoo f = new A();

f is A
interface IFoo {}
class A : IFoo{}
IFoo f = new A();

f is A
Result: bool
True
True
Compile: 445.172ms | Execution: 33.085ms | React with ❌ to remove this embed.
Angius
Angius15mo ago
Yep
joren
jorenOP15mo ago
that cryingcat
Angius
Angius15mo ago
It's an upcast And is is for pattern matching It's extremely useful, believe me Especially with list patterns and all
joren
jorenOP15mo ago
but how do virtual methods differ in C# do they create vtables as in C++ or is that knowlegde not applicable
Angius
Angius15mo ago
A virtual method is an explicit signal that it's expected to be overridden
joren
jorenOP15mo ago
this is absurd, the moment one would ISoundMaker dog = new Dog() { Name = "Doggo" }; you'd get a compiler error in C++ unless its a pointer
Angius
Angius15mo ago
Well Dog is a reference type So kinda-sorta a pointer lol
joren
jorenOP15mo ago
that would also not compile in C++ its weird to me that ISoundMaker dog = new Dog() { Name = "Doggo" }; is basically treated as a pointer but if that were the case are there vtables generated, I assume not? it just holds an alias to Dog() instance and allows it since its a reference type and its a child class of ISoundMaker ..?
Angius
Angius15mo ago
Honestly, not sure about the nitty-gritty of how it works People in #allow-unsafe-blocks might have a better idea about vtables and what not
joren
jorenOP15mo ago
I'll have a look at that channel after I've read the whole polymorpishm post on the officials docs for now my knowledge of interfaces should suffice I guess im just being pragmatic for no reason, it matters when I have to dive deep which isnt soon
MODiX
MODiX15mo ago
joren
REPL Result: Failure
interface ISoundMaker
{
public string Name;
}
interface ISoundMaker
{
public string Name;
}
Exception: CompilationErrorException
- Interfaces cannot contain instance fields
- Interfaces cannot contain instance fields
Compile: 408.788ms | Execution: 0.000ms | React with ❌ to remove this embed.
joren
jorenOP15mo ago
why's this though, since its just a contract you'd think just declaring it would be ok
Angius
Angius15mo ago
Well, yeah, it's a field. An implementation detail You'll need to make it a property
joren
jorenOP15mo ago
my terminology is not up-to-date with the csharp conventions
Angius
Angius15mo ago
$structure
MODiX
MODiX15mo ago
namespace Namespace;

[Attribute]
public class Class
{
public string PublicField;
private bool _privateField;
protected double protectedField;

public int PublicProperty { get; set; }

public Class() {} // Constructor

public void Method(int parameter)
{
var localVariable = parameter;
}
}
namespace Namespace;

[Attribute]
public class Class
{
public string PublicField;
private bool _privateField;
protected double protectedField;

public int PublicProperty { get; set; }

public Class() {} // Constructor

public void Method(int parameter)
{
var localVariable = parameter;
}
}
For C# versions older than 10, see $StructureOld
Angius
Angius15mo ago
Here's a cheat sheet
joren
jorenOP15mo ago
so a field is basically a class member
Angius
Angius15mo ago
Everything inside of a class is this class's member
joren
jorenOP15mo ago
a property is basically a class member with certain properties, like get; and set;? by C++'s terminology you have: class members and class methods and thats it
Angius
Angius15mo ago
Right, yeah
joren
jorenOP15mo ago
its just to compare for me, sorry! a property just being a class member with extra utility so to say? properties being set; get; init; etc? basically when the { ... } is introduced
Angius
Angius15mo ago
Yeah
joren
jorenOP15mo ago
interface ISoundMaker
{
public string Name { get; }
void MakeSound();
}

class Dog : ISoundMaker
{
public string Name { get; init; }

public void MakeSound()
{
Console.WriteLine("Dog barks.");
}
}
interface ISoundMaker
{
public string Name { get; }
void MakeSound();
}

class Dog : ISoundMaker
{
public string Name { get; init; }

public void MakeSound()
{
Console.WriteLine("Dog barks.");
}
}
so in this case the property Name in ISoundMaker tells us that you have to define get; in its child classes correct, and then we can add others like init ourselves if we seem fit
MODiX
MODiX15mo ago
joren
REPL Result: Failure
interface ISoundMaker
{
public string Name { set; }
void MakeSound();
}

class Dog : ISoundMaker
{
public string Name { get; init; }

public void MakeSound()
{
Console.WriteLine("Dog barks.");
}
}
interface ISoundMaker
{
public string Name { set; }
void MakeSound();
}

class Dog : ISoundMaker
{
public string Name { get; init; }

public void MakeSound()
{
Console.WriteLine("Dog barks.");
}
}
Exception: CompilationErrorException
- 'Dog' does not implement interface member 'ISoundMaker.Name.set'. 'Dog.Name.init' cannot implement 'ISoundMaker.Name.set'.
- 'Dog' does not implement interface member 'ISoundMaker.Name.set'. 'Dog.Name.init' cannot implement 'ISoundMaker.Name.set'.
Compile: 664.426ms | Execution: 0.000ms | React with ❌ to remove this embed.
joren
jorenOP15mo ago
shouldnt work nice ok, makes sense
Accord
Accord15mo ago
Was this issue resolved? If so, run /close - otherwise I will mark this as stale and this post will be archived until there is new activity.
Want results from more Discord servers?
Add your server