Ask coding questions

← Back to all posts
What design pattern should I use for specific multiple inheritance?
DynamicSquid (4532)

Let's say I have an interface called Squid.

interface Squid {
  void DisplayInfo();
}

And we have a bunch of different types of squids:

class AquaticSquid inherits Squid {
  void DisplayInfo() {}
  void Swim() {}
}
class LandSquid inherits Squid {
  void DisplayInfo() {}
  void Crawl() {}
}


class BasicSquid inherits Squid {
  void DisplayInfo() {}
  void BasicAttack() {}
}
class AdvancedSquid inherits Squid {
  void DisplayInfo() {}
  void AdvancedAttack() {}
}

Here's everything a squid can be:

aquaticland
basicbasic-aquaticbasic-land
advancedadvanced-aquaticadvanced-land

How would I go about create an instance of a squid? Should I go about creating 4 classes BasicAquaticSquid, BasicLandSquid, AdvancedAquaticSquid, AdvancedLandSquid like this:

class BasicAquaticSquid inherits BasicSquid, AquaticSquid {
  void DisplayInfo() {}
  void Swim() {}
  void BasicAttack() {}
}

BasicAquaticSquid squid;
squid.Swim();

I think that's called the Abstract Factory method? It seems very tedious though. Any better way of doing so?

Thanks

Answered by xxpertHacker (648) [earned 5 cycles]
View Answer
Commentshotnewtop
xxpertHacker (648)

I personally don't use classes, I don't know why, I just don't like OOP code, but, I recommend just using whatever is simplest and most maintainable.

...

Honestly, I sat here for more than 15 minutes, trying to think of a good way to create these interfaces, but nothing sounds good.

I have no clue how you should do this, maybe go look at some gaming industry's source code?

Although, maybe it's hard to understand it because of the lack of information.

What makes a squid advanced or basic?

How different is an aquatic squid from a land squid?

Depending on how you define the differences between them, you might not even need separate classes at all.

DynamicSquid (4532)

@xxpertHacker The main difference are the functions. Each class has it's own unique set of functions. For example AquaticSquid has Swim(), Drown(), and Float(). I'll try to reduce the number of functions I have, but for the time being, each class has it's own funtcions.

xxpertHacker (648)

@DynamicSquid I'm not sure if this is a good way of setting it up, although, I am not a game developer either. (This is a game you're attempting to program, right?)

Now, I have no clue how your game is going to work nor do I have many details, but if the squids are capable of battling each other, ideally, you would want a generic setup that would allow you to pit any two squids or players against each other, at runtime, without compiling a separate code template for every single possible combination of creature that could meet.

Let's say the core of the game revolves around pitting squids against each other (wait this sounds like Pokemon or something, eww), you have a function called battle.
It takes two formal parameters, each being the squid to take a side in the battle.

How would you set it up, if each squid has different methods? Duck typing isn't safe. And compiling something like battle<Squid1, Squid2>(Squid1 squid1, Squid2 squid2); for every possibility isn't fun either.

Also, in every game that I've played, to date, every different player could all do similar things at a high-level, they just have different animations.

Think of a shooting game, each firearm deals damage, and has velocity, yet they have different animations, sounds, trajectories, and numbers associated with their capabilities.

Personally, I might do something generic, like .move, .primaryAttack, .secondaryAttack, .canSwim, and give them all different implementations, but I'm not sure if it's the best way to do this, or if anyone else would agree with a structure like this.

DynamicSquid (4532)

@xxpertHacker It's not really a game, more like a "museum" lol. But yeah, I think you're right. I want polymorphism (what's short form for "polymorphism"? is it "polymorph", or can I say "poly") to work as well, so I probably have to make generic methods.

Thanks for the help though!

xxpertHacker (648)

@DynamicSquid Oh, oops, I presumed that it was a game, or something of the sort based on your initial example:

void DisplayInfo() {}
void Swim() {}
void BasicAttack() {}

BasicAttack seems like something that you would find in game, and considering that we're on Repl... it wouldn't normally be a bad guess.

But, good luck with your program!

firefish (877)

@DynamicSquid use the duplicate macro in the duplicate crate

// eek rust syntax highlighting
extern crate duplicate;
use duplicate::duplicate;

trait Squid {
  fn display_info(&self);
  fn new() -> Self;
}

#[duplicate(
  typ atk mve;
  [ AdvancedAquatic ] [ advanced_attack ] [ swim ];
  [ BasicAquatic ] [ basic_attack ] [ swim ];
  [ AdvancedLand ] [ advanced_attack ] [ crawl ];
  [ BasicLand ] [ basic_attack ] [ crawl ];
)]
trait typ {
  fn atk(&self);
  fn mve(&self);
}

/* ... */
fn main() {}

(will invite you to said repl)
Stack Overflow link

firefish (877)

@DynamicSquid also come on the NightLang pr #65

xxpertHacker (648)

@firefish Why did I not think of that!? Rust duplicate crate, there we go, problem solved.

firefish (877)

@xxpertHacker I did spend some time combing through Stack Overflow, as you can tell by the link

firefish (877)

@DynamicSquid @Lethdev2019
Slice, dusk, and night... what do you think?

(dusk is smaller because it ain't a language)

Lethdev2019 (197)

@firefish i like it but when are we gonna work on slice?

firefish (877)

@Lethdev2019 I am, every day. Working on the SoN VM

firefish (877)

@Lethdev2019 Well how? We can start by making the interpreter, I mean all the sliec stuff is in the SoN VM proto.md, so check there

Lethdev2019 (197)

also - i am using linux now. @firefish

firefish (877)

@Lethdev2019 Same, I like to use my dualboot, but I'm not using it atm because I want to do some dev now, not wait an hour to update it to Fedora 33

firefish (877)

@Lethdev2019 Hi, come on the repl named "SoN-VM"

xxpertHacker (648)

@firefish I'm surprised that stuff on Rust can even be found, seeing as so few people use it. But honestly probably a better answer than mine.

firefish (877)

@xxpertHacker

so few people use it

how uncultured are you

xxpertHacker (648)

@firefish What do you mean? How am I uncultured because so few people use the Rust programming language relative to other languages?

firefish (877)

@xxpertHacker You are deluded. Google agrees with me:

ignore the last bit

xxpertHacker (648)

@firefish No, it doesn't?
The last sentence supports me, not you.
I'm among the 5% of people who have used the language.

firefish (877)

@xxpertHacker but 86% of people said they were keen on learning it

xxpertHacker (648)

@firefish Yeah, that's cool.. but they haven't started. Actons are worth more than words.
Could I have asked one of the people who are keen on learning it about the duplicate crate? No, because they have no clue what a crate even is, because they want to learn it, but they haven't started.

Thus we return to what I had originally said:

...so few people use it.

DynamicSquid (4532)

@xxpertHacker I agree. Rust can actually be a really good language if you know how to use it. Otherwise it seems like C++ but with restrictions and weird rules

firefish (877)

@DynamicSquid Learn the rules, and you will forget how to code in C++ (lol not kidding)

DynamicSquid (4532)

@firefish lol. I like C++ since it allows you to do whatever you want. Rust is like:

Is that unsafe code!??!?! ERROR!

C++ is like:

Is that unsafe code?? Okay, lemme provide you with some additional features that you can abuse
xxpertHacker (648)

@DynamicSquid Whoa whoa, you need to learn the language.
Once you have, you'll realize C++ is the language without restriction and with weird rules. Rust is a language that makes sense.

Also, it has one major advantage over C++: there is no undefined behavior whatsoever.

You can have a multi-threaded program, knowing everything will always run flawlessly (okay, it might deadlock, but still).

You will never run into concurrent reading/writing problems.

You should never get a system floating-point exception.
Arithmetic should never overflow and give weird results.

You can't perform certain operations in Rust, but you can in C++:

println!("{}", 'a' / 'b'); // error, what are you doing with your life?
std::wcout << ('a' / 'b') << '\n';

You can't read uninitialized data:

let x: i32;
println!("{}", x); // error

You can't read out of bounds memory.

You get where I'm going, the list continues, you can't do a bunch of dumb stuff, do you know what that means?
Every package you import and use should work correctly, without having to review the code.

It doesn't have classes, so if you like OOP styled code, you'll have to learn how to write idiomatic Rust.

firefish (877)

@DynamicSquid Well What if you reference something you aren't supposed to, and then you program starts overwriting itself in memory. Oh boy, can that be abused

firefish (877)

@xxpertHacker

how to stuff

I wouldn't have used the verb stuff in THAT context but whatever you say...

xxpertHacker (648)

@firefish Oops, I edited half of the sentence without reconnecting it; fixed.

firefish (877)

@xxpertHacker

<I wouldn't have used the ver

What did the rest say?

xxpertHacker (648)

@firefish What are you talking about?

firefish (877)

@DynamicSquid Night can be BOTH interpreted AND bytecodce

xxpertHacker (648)

@firefish It was deleted for a reason :)

firefish (877)

@xxpertHacker I bet it ended with
b stuff in that context or something along those lines

firefish (877)

@xxpertHacker And then you probably said something indecent in the context in which you WOULD use it.

xxpertHacker (648)

@firefish CPython and the V8 JavaScript engine both just interpret bytecode instead of text, seems more performant, why not just use bytecode?

xxpertHacker (648)

@firefish No, I had actually questioned how "stuff" is even a verb, before remembering that it could mean to put something into a small space.

firefish (877)

@Dynamicsquid @xxpertHacker a.k.a. @StudentFires forgot to ping you, here's what he said:

CPython and the V8 JavaScript engine both just interpret bytecode instead of text, seems more performant, why not just use bytecode?

xxpertHacker (648)

@firefish Who's @StudentFires? And no, I was responding to your message, which was directed towards DynamicSquid.

firefish (877)

@xxpertHacker That's you, remember? (aight this guy has memory loss)

xxpertHacker (648)

@firefish Nope, no recollection of that Repl.it user whatsoever.

firefish (877)

@xxpertHacker I hope you're joking because click on the link @StudentFires and you will see that it leads to your own profile

xxpertHacker (648)

@firefish Weird, I'll probably go report that bug later, when I have time.

firefish (877)

@xxpertHacker And this:

also i know you are pulling my leg

firefish (877)

@xxpertHacker And what happened to changing repl.it at it's core

DynamicSquid (4532)

@firefish, @xxpertHacker Should unsafe programming practices be the programmer's fault, or the language's fault?

firefish (877)

@DynamicSquid The programmer's fault in C/C++, in rust it's the programmer's fault if you put an unsafe block

DynamicSquid (4532)

@firefish I feel like it should be the programmers fault. That's why I like C++ so much, you can do whatever you want

firefish (877)

@DynamicSquid it is the progrmammers fsualt

xxpertHacker (648)

@firefish But... fish don't have legs...

xxpertHacker (648)

@DynamicSquid To that, I must ask you the following:

In a strongly-typed, and statically typed language, should type safety be the programmer's fault, or the language's fault?

Should you run a compiler on a text file, and get a properly working executable, or an improperly-working executable?

Should source code that was developed on a Windows computer be capable of being compiled on a Linux, and run just as it had done on the Windows, without change?

Should undefined behavior be allowed to even exist?

DynamicSquid (4532)

@xxpertHacker Yeah, good points, can't really argue with that

DynamicSquid (4532)

@xxpertHacker But again, I think the feeling of "this language won't let me do this" is harmful since it's limiting programmers in what they can do. Programming's (I'm talking about low level programming since that's obviously the best) all about working with the computer, but if you restrict some of the things you can do with the computer, well then you're not really working with the computer, if that makes any sense

firefish (877)

@xxpertHacker Where did I mention legs...

xxpertHacker (648)

@DynamicSquid We can both agree on what to choose from those questions I raised, and Rust made the right choices.

Simply think of the restrictions like you think of what you can do in C/C++ on a pointer.

Let's start, what is a pointer?
Computers only understand numbers, a pointer is a literal integer, yet... in a way, it's not.

It is an integer, yet it simply is used to load and store memory at the specific point that it "points" to.
Why do I bring this idea up at all?
Because they are an abstract idea, but they have restrictions.

char const * const x = "test"; "test\0"

decltype(auto) est = test + 1; // "est\0"

decltype(auto) questionableCode = test >> 3; // not allowed, yet... allowed on integers

decltype(auto) moreQuestionableCode = test & 1;

Does that seem like a weird restriction? Hopefully not. Yet it makes perfect sense to restrict what can be done in some cases, yet most of the time, C++ just lets you do whatever you want, whether or not it makes sense at all.

xxpertHacker (648)

@firefish You said that I was "pulling your leg," but you're a fish.

DynamicSquid (4532)

@xxpertHacker give him a couple million years and he'll grow legs

DynamicSquid (4532)

@xxpertHacker No, squids can't evolve. If you look closely at the hierarchy:

class Cephapod final // notice the 'final' keyword here
  : public Animal;
firefish (877)

@xxpertHacker So there are these things called idioms

xxpertHacker (648)

@firefish Whoa, idioms of the sea? I don't know many fish idioms, sorry.

DynamicSquid (4532)

@xxpertHacker But the whole point is not having restrictions. If I want to shift bits, I should be able to shift bits. The idea of "abstraction" I think is just a way for me to better communicate what I want to do with the computer

xxpertHacker (648)

@DynamicSquid Lmao, you can be the first by learning Rust though.

DynamicSquid (4532)

@firefish, @xxpertHacker I am so confused, we're having like 2 conversations at the same time

firefish (877)

@DynamicSquid @xxpertHacker is trying to annoy me, by being an idiot

xxpertHacker (648)

@DynamicSquid Yeah... it could be confusing for you, being caught in the middle, and being the author of this post, meaning you get every message.

DynamicSquid (4532)

@xxpertHacker, @firefish you guys making fun of each other reminds me:

your mamma is so fat that she can sit on a binary tree and turn it into a linked list in O(1) time

DynamicSquid (4532)

@xxpertHacker, @firefish gotta go now. probably gonna come back to like 50 notifications :/

xxpertHacker (648)

@DynamicSquid The idea isn't restriction at all, more likely, it's explicitness.

Often times, in source code, when you see something weird, one of thee things are true:

  • You stopped and said, "what am I looking at?"
  • There is a comment explaining the apparent nonsense, explaining that it is not nonsense, but some weird technique.
  • You actually understood what you saw, because you've seen it before, or had actually done it before.

If you've ever seen a weird piece of code before, you should agree.

The first possibility is very likely, and it exists because languages let people do weird stuff. This possibility does not exist within Rust.

The second exists for the same reason as the first and is due to a lack of language-level support for whatever they did, or because they were lazy. What if you provide language-level support for this?

The third possibility is very unlikely and doesn't need to exist, because weird code practice shouldn't need to exist.

xxpertHacker (648)

@DynamicSquid We're not even making fun of each other.

firefish (877)

Hi, don't mind me just testing a bot

TANMAYBAGADIA (45)

sorry if it is java then i can't help as i have not yet learned it!!
sorry :(

realTronsi (840)

@TANMAYBAGADIA why did you reply then lmao

DynamicSquid (4532)

@TANMAYBAGADIA Thanks for the help lol. But you can do this in any language

TANMAYBAGADIA (45)

@DynamicSquid oh ok ,but sorry i was not able to give u answer

Coder100 (12434)

I feel like what should happen is (you forgot your semis, that bothered me a lot):

class LandSquid
{
private:
  SomeTypeEnum advanced;
public:
  void DisplayInfo() {/* use that advanced variable to customize */}
  void move() {/* technically it would be swim, but this is called consistency */}
};

class AquaticSquid
{
private:
  SomeTypeEnum advanced;
public:
  void DisplayInfo() {/* use that advanced variable to customize */}
  void move() {/* technically it would be crawl, but this is called consistency */}
};

and you now see you could even make this only one class! Maybe even polymorphism idk

DynamicSquid (4532)

@Coder100 Also what is SomeTypeEnum advanced?

DynamicSquid (4532)

@Coder100 if statements would just get too ugly, no way

DynamicSquid (4532)

@Coder100 if statements means I would need to pass in parameters, and it couldn't work well with other interfaces, and it's not modular, etc.

Coder100 (12434)

hm, maybe im not understanding your question right, sorry :( @DynamicSquid

Coder100 (12434)

i was thinking them more similar than not sorry :( @DynamicSquid

Coder100 (12434)

do they all have similar moves? @DynamicSquid

Coder100 (12434)

advanced squid for land and aquatic have same moves just reworded and same for basic @DynamicSquid

firefish (877)

@Coder100 what is this

public:
    void Swim();

nonsense just use
public void Swim():w
oh no the old VIM habits

Coder100 (12434)

@firefish i mean in C++ that's what we do

firefish (877)

@Coder100 Well that's my C# brain for you then

xxpertHacker (648)

@firefish I hate Java and C# for making people do this:

class T {
    public void foo() { ... }
    public void bar() { ... }
    public void baz() { ... }
    public void quux() { ... }
}

When C++ just says:

struct T {
    void foo() { ... }
    void bar() { ... }
    void baz() { ... }
    void quux() { ... }
}
DynamicSquid (4532)

@Coder100 no the whole point is that they're different functions

firefish (877)

@xxpertHacker what the hell in C# structs can have methods

xxpertHacker (648)

@firefish In C#, What is the difference between a struct and a class?

firefish (877)

@xxpertHacker Structs are inline, and classes are allocated on the heap.

xxpertHacker (648)

@firefish Hmm... well, I was using C++ structs as public classes.

Even then, it could've been this:

class T {
    public:
    void foo();
    void bar();
    void baz();
    void quux();
};

Still less typing.

firefish (877)

@xxpertHacker Is you ask me, that public: thing looks out of place and hideous

Coder100 (12434)

i wish all langs had that syntax, @C# @firefish

xxpertHacker (648)

@firefish Thus why I simply prefer using the struct keyword in C++ instead, it implies it already, while not looking weird.

But still, public/private fields are better than tediously putting them one by one.

firefish (877)

@xxpertHacker In C++ structs can have methods too, only in plain C you cannot

xxpertHacker (648)

@firefish In C++, structs are perfectly equivalent to classes, with one difference. They are public by default.

class T {
    private: // redundant
};

struct T {
    public: // redundant
};

So, yes, it makes perfect sense that they would have methods.

Although, C structs can be used as namespaces, by using function pointers.

struct T {
    int const (* const method)(T const);
};

Eh, still not a method.

firefish (877)

@xxpertHacker Yes, still not a method.
But in Rust there are no such thing as classes! Only structs and enums, in which you can implement wither your own methods, or a trait (the closest thing rust has to an interface)

Coder100 (12434)

me likey c++ rust not make me commit unsafe @firefish

firefish (877)

@Coder100 do what you "likey", grilled cookie (or is it cookey now?)

CSharpIsGud (794)

@firefish You can, it's just ugly because you have to use function pointers.

If you really want to you can give them self references as the first argument.

CSharpIsGud (794)

@xxpertHacker structs are value types, no default constructor, new operator isn't needed to make them, they can't inherit from structs or classes, no non-static variable initializers

xxpertHacker (648)

@CSharpIsGud Assuming you're talking about C# structs, that'll be worth keeping in the back of my mind, should I ever find myself debugging C# or learning the language.

Also, I presume the unnecessary new is because they aren't heap allocated, is C#'s new related to heap allocation at all?

CSharpIsGud (794)

@xxpertHacker I think they just did new because it was a thing, new doesn't really make a difference.
C# can allocate structs on the heap if they are located inside a class.

xxpertHacker (648)

@CSharpIsGud Well, of course, if a class instance is heap-allocated, then I would expect all of its members to be on the heap too, including structs.

But, since you're here, and you use OOP styled code (right?), you seem like you would be among the most capable programmers here capable of helping out @DynamicSquid with his question.

CSharpIsGud (794)

@xxpertHacker even in C# I avoid inheritance everywhere possible unless it actually makes what I want easier.

Coder100 (12434)

Table (for reference)

aquaticland
basicbasic-aquaticbasic-land
advancedadvanced-aquaticadvanced-land
Coder100 (12434)

for others, i made a tiny table:

well that's just great tables aren't supported no more
well that's just great i forgot how to do tables

DynamicSquid (4532)

@Coder100 wait I though tables didn't work here

Coder100 (12434)

anyways check out the other comment imma try to think of how to solve your problem @DynamicSquid

DynamicSquid (4532)

@Coder100

VersionDescriptionProgress
v1.0functions to aid with arrayscomplete
Coder100 (12434)

anyways check out my answer is it even good @DynamicSquid

Coder100 (12434)

hol' up i thought this was C++, and then i looked at the interface and I was like oh wait nvm @DynamicSquid

DynamicSquid (4532)

@Coder100 it doesn't matter what language it is

Coder100 (12434)

@DynamicSquid that would be pog if my ideas actually came to life :D

DynamicSquid (4532)

@Coder100 But in your example you combined Swim and Crawl, but they need to be separate functions

Coder100 (12434)

wait but you could add if statements:

if (type == WATER)
{
  //
}
else if (type == LAND)
{
  //
}

@DynamicSquid

firefish (877)

@DynamicSquid lol le sqdlib (also come onto le pr #65 on NIGHT)

firefish (877)

@Coder100 No if statements, THIS IS A FLIPPING INTERFACE, you can implement them how you want, so move() does different things depenfing on whether it's land or water