C
C#13mo ago
Jona4Play

✅ Issues with interfaces and generic classes

I want to create a general-practise chemistry model in C#. I have created some basic objects and created a few interfaces to specify the interactions between the classes. Now I have an issue when trying to create an instance with a generic class only allowing a certain interface. I have attached a picture to make the relations a bit clearer. Now for the issue Compound implements ISolute as well as IAmount I now pack it into the Mol class which looks like this
public class Mol<IAmount>
{
public double Amount { get; set; }
public required IAmount Compound { get; set; }

public static Mol<IAmount> Of(IAmount compound, double amount)
{
return new Mol<IAmount>() { Amount = amount, Compound = compound };
}
}
public class Mol<IAmount>
{
public double Amount { get; set; }
public required IAmount Compound { get; set; }

public static Mol<IAmount> Of(IAmount compound, double amount)
{
return new Mol<IAmount>() { Amount = amount, Compound = compound };
}
}
Which works fine since compound implements it. Now I want to create a solution out of it with this method of the solution class:
public static Solution Of(Mol<ISolute> solute, Volume<ISolvent> solvent)
{
return new Solution() { Solute = solute, Solvent = solvent };
}
public static Solution Of(Mol<ISolute> solute, Volume<ISolvent> solvent)
{
return new Solution() { Solute = solute, Solvent = solvent };
}
Where the problem arises of the ISolute interface not corresponding with the type Compound eventhough ISolute is implemented by Compound and inherits from IAmount
No description
48 Replies
Jona4Play
Jona4PlayOP13mo ago
Also just for reference this is the corresponding unit test
[<Fact>]
let ``Create a 1M solution of H2SO4 in water`` () =
let sulfuricAcid = Mol.Of(new Compound("Sulfuric acid", "H2SO4"), 1)
let water = Volume.Of(new Compound("Water", "H2O"), 1)
let solution = Solution.Of(sulfuricAcid, water)
Assert.Equal(1.0, solution.Concentration)
[<Fact>]
let ``Create a 1M solution of H2SO4 in water`` () =
let sulfuricAcid = Mol.Of(new Compound("Sulfuric acid", "H2SO4"), 1)
let water = Volume.Of(new Compound("Water", "H2O"), 1)
let solution = Solution.Of(sulfuricAcid, water)
Assert.Equal(1.0, solution.Concentration)
This shows a pre compile error for both ISolute and ISolvent
Luxx
Luxx13mo ago
I don’t see that compound implements Amount from ISolute The chemist in me also suggests renaming “Concentration” to “Molality”?
DΣX
DΣX13mo ago
i dont think i fully understand, but what if u create interface ICompound, implement IAmount and ISolute in it. use the new interface anywhere where u r having the compound. will this solve your problem?
Jona4Play
Jona4PlayOP13mo ago
The interfaces are empty as of now. Maybe I misunderstood you. Also yes. Renaming to molarity makes sense Not sure but dont think so. Both ionized Elements and Compounds can be Solutes. Only compounds can be solvents. And both can be taken quantities of in Mol. That's why I thought I'd have the Mol generic as a wrapper around it which entails the quantity in addition to some IAmount of element or compound. But extracting that to a new ICompound interface makes sense
Jona4Play
Jona4PlayOP13mo ago
This is the updated diagram
No description
DΣX
DΣX13mo ago
i really have no idea about chemistry, and even less so in english. so just inform me if that helps in any way. i wouldnt understand just by the diagram 😄
Thinker
Thinker13mo ago
Also you're writing your tests in F#?
DΣX
DΣX13mo ago
wait, this is f#? you can name functions with complex strings in f#? 😄
Thinker
Thinker13mo ago
yea
Jona4Play
Jona4PlayOP13mo ago
Yes XD
Thinker
Thinker13mo ago
is that the only reason you're using F#...?
Jona4Play
Jona4PlayOP13mo ago
Nope. Just learned to love the language. Also less boilerplate because I already hate writing unit tests
Thinker
Thinker13mo ago
makes sense
Jona4Play
Jona4PlayOP13mo ago
Oh do I see lambda calc in your bio?
Thinker
Thinker13mo ago
ye I'm working on a lambda calc repl in Haskell for fun Haven't used F# a ton but wanna try it out more tbh
Jona4Play
Jona4PlayOP13mo ago
Great to get work done quick. Kinda like python, although it has on par modeling ability with C#
Thinker
Thinker13mo ago
Yeah can see that Anyway sorry for diverting the thread
Jona4Play
Jona4PlayOP13mo ago
All good. Im working on a different part. Hoping a good idea pops up Might add a github link too. Maybe it's beneficial to actually have others see the shit code I wrote
Jona4Play
Jona4PlayOP13mo ago
GitHub
GitHub - Jonathan-Schaefer-git/DotChem
Contribute to Jonathan-Schaefer-git/DotChem development by creating an account on GitHub.
Luxx
Luxx13mo ago
Sorry, I misunderstood the Diagram. I read the IAmount as a property Amount. I’m can tell from the diagram alone why it wouldn’t resolve. Is there a specific compile error?
Jona4Play
Jona4PlayOP13mo ago
Nope. Sadly not. I honestly dont quite understand the error. It says that there is a type mismatch. I suspect it being the use of the Mol<IAmount> Wrapper class causing this
Luxx
Luxx13mo ago
If you remove ISolvent from ICompound, does it work?
Jona4Play
Jona4PlayOP13mo ago
Just says Mol<Compound> is not compatible with Mol<ISolute> eventhough Compound implements both IAmount and ISolute No. Same error Maybe there is a way around this
Luxx
Luxx13mo ago
Try to simplify it in another project with just IMol, ICompound, and IAmount? Add one interface at a time.
Jona4Play
Jona4PlayOP13mo ago
Ok sure. That makes sense 👍
Omnissiah
Omnissiah13mo ago
Just says Mol<Compound> is not compatible with Mol<ISolute>
bot Mol<> is not extending anything Mol<type1> is not compatible with Mol<type2> whatever the case they are two different types not even the generic type of Mol<> has a constraint
Jona4Play
Jona4PlayOP13mo ago
But ISolute inherits IAmount
Omnissiah
Omnissiah13mo ago
bit Mol doesn't know it
Jona4Play
Jona4PlayOP13mo ago
Well shit. How would you correct for that?
Omnissiah
Omnissiah13mo ago
maybe class Mol<T> where T:ICompound
Luxx
Luxx13mo ago
Was about to suggest this as well
Omnissiah
Omnissiah13mo ago
yeah although inheritance is not the easiest thing to deal with
Jona4Play
Jona4PlayOP13mo ago
Thing is though, that this isnt possible. It should be the IAmount interface as mol of elements are possible. So should I change it to IAmount? Wouldn't this have the same issue with interface inheritance as beforehand?
Omnissiah
Omnissiah13mo ago
use whatever the base interface is i put ICompound there but not with the entire knowledge of the project ah ok i read the diagram in reverse
Jona4Play
Jona4PlayOP13mo ago
ok give me a minute Yeah arrows are fucked up. It the VS designer thing Ok. I believe I messed up, as it shows the same thing but with it now being broader the error changed
public class Mol<T> where T:IAmount
public class Mol<T> where T:IAmount
Is the header for the Mol class But its now Mol<IAmount> is not compatible with Mol<ISolute> Which means its still doesnt recognize the inheritance of the interface
let a = Mol.Of(new Compound("", ""), 1)
let b : Mol<ISolute> = Mol.Of(new Compound("", ""), 1)
let a = Mol.Of(new Compound("", ""), 1)
let b : Mol<ISolute> = Mol.Of(new Compound("", ""), 1)
This has the same error
Omnissiah
Omnissiah13mo ago
because they still are two different types you would have to make Mol inherit from something not generic or use the same generic type
Jona4Play
Jona4PlayOP13mo ago
I... dont think I fully understand what you mean by that. Could you please elaborate or give me an example?
Omnissiah
Omnissiah13mo ago
(basically it means class Mol<IAmount> : IMol, so that IMol m could hold every Mol<>, then you cast as needed; if you look at c# collections they have a common non-generic inheritance) as Luxx said, i would just try starting with Mol with no generics, since at the moment it doesn't seem you need it if you then need more, then you probably should read about covariance and contravariance but i would try to stay as simple as possible
Jona4Play
Jona4PlayOP13mo ago
Ok thanks
Omnissiah
Omnissiah13mo ago
still, this should work
var a = Mol<IAmount>.Of(new Compound1("", ""), 1);
var b = Mol<IAmount>.Of(new Compound2("", ""), 2);
a = b;
var c = Mol<IAmount>.Of(new Solute3(), 3);
a = c;
var a = Mol<IAmount>.Of(new Compound1("", ""), 1);
var b = Mol<IAmount>.Of(new Compound2("", ""), 2);
a = b;
var c = Mol<IAmount>.Of(new Solute3(), 3);
a = c;
but it's kinda delicate and if you screw up it could throw exception at runtime
Jona4Play
Jona4PlayOP13mo ago
Yeah this would work. But I think I'll try the approach you described first
g00dSoup
g00dSoup13mo ago
What tool did you use to create the diagram? Looks so neat
Jona4Play
Jona4PlayOP13mo ago
Visual Studio Class Designer. Its installable through the VS installer just drag in a whole project and it auto generates it
g00dSoup
g00dSoup13mo ago
Jona4Play
Jona4PlayOP13mo ago
No description
Jona4Play
Jona4PlayOP13mo ago
I have implemented a simpler working version, although I'd like to pick up the Generic version tomorrow
Accord
Accord13mo 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.
Jona4Play
Jona4PlayOP13mo ago
Thanks to everyone @here. Thanks to your input I was able to figure it out 👍
Want results from more Discord servers?
Add your server