Abstract base class design in Go vs C++












-4















I am still learning the Go way of doing things, coming from a C++ background. I am looking for feedback contrasting OOP inheritance to interface composition.



I have a design situation in a Go program where, if I was implementing in C++, I would solve with an abstract base class.



Suppose I need a base class, which has many implementors. The base class has shared methods that do work on abstract data items. Different Worker implementations provide CRUD operations on different item types, but workers all use the shared methods of the base class for general work.



In C++ I might do it this way



class IItem
{
// virtual methods
};

class IWorker
{
public:
// one of many virtual functions that deal with IItem CRUD
virtual IItem* createItem() = 0;

// concrete method that works on interfaces
void doWork()
{
IItem* item = createItem();
// do stuff with an IItem*
}

};


class Toy : public IItem
{

};

// one of many kinds of workers
class ElfWorker : public IWorker
{
public:

ElfWorker()
{
// constructor implicitly calls IWorker()
}

IItem* createItem() override
{
return new Toy;
}
};


In Go you don't have abstract virtual methods such as IWorker::createItem(). Concrete classes need to supply the base with an interface or function that do the right thing.



So I think it is the case that the Go code the ew.ItemCRUD interface has to be explicitly set with a pointer to an ElfWorker.



The elf knows how to createItem(), which in his case happens to be Toy object. Other workers would implement their own ItemCRUD for their data objects.



type Item interface {                         
// various methods
}
type ItemCRUD interface {
create() Item
// other CRUD
}

type Worker struct {
ItemCRUD // embedded interface
}
func (w *Worker) doWork() {
item := w.create()
// do stuff with item
}

type Toy struct {
}

type ElfWorker struct {
Worker // embedded
// ..
}

func NewElfWorker() *ElfWorker {
ew := &ElfWorker{}
ew.ItemCRUD = ew // <-- #### set Worker ItemCRUD explicitly ####
return ew
}

func (ew *ElfWorker) createItem() Item {
return &Toy{}
}
// more ElfWorker Item CRUD
func bigFunction(w *Worker) {
// ...
w.doWork()
// ..
}


So the part that I am wrestling a bit with is explicit setting. Seems like the "Go way" of composition does require this explicit step if I want the base Worker class to provide shared methods on Items.



Thoughts?










share|improve this question




















  • 7





    Drawing parallels between C++ and any other language can prove to be counter-productive.

    – Ron
    Jan 2 at 18:30











  • first derivative to @Ron’s comment: Applying patterns found in other programming languages to Go can prove counter-productive.

    – Markus W Mahlberg
    Jan 2 at 23:43











  • I'm voting to close this question as off-topic because it shouldbe moved to Codereview

    – thst
    Jan 3 at 8:11











  • Down vote because I asked for feedback on a design choice? I think I clearly stated I was looking to learn? I stated up front the languages would solve the problem in different ways.

    – meissnersd
    Jan 3 at 19:24
















-4















I am still learning the Go way of doing things, coming from a C++ background. I am looking for feedback contrasting OOP inheritance to interface composition.



I have a design situation in a Go program where, if I was implementing in C++, I would solve with an abstract base class.



Suppose I need a base class, which has many implementors. The base class has shared methods that do work on abstract data items. Different Worker implementations provide CRUD operations on different item types, but workers all use the shared methods of the base class for general work.



In C++ I might do it this way



class IItem
{
// virtual methods
};

class IWorker
{
public:
// one of many virtual functions that deal with IItem CRUD
virtual IItem* createItem() = 0;

// concrete method that works on interfaces
void doWork()
{
IItem* item = createItem();
// do stuff with an IItem*
}

};


class Toy : public IItem
{

};

// one of many kinds of workers
class ElfWorker : public IWorker
{
public:

ElfWorker()
{
// constructor implicitly calls IWorker()
}

IItem* createItem() override
{
return new Toy;
}
};


In Go you don't have abstract virtual methods such as IWorker::createItem(). Concrete classes need to supply the base with an interface or function that do the right thing.



So I think it is the case that the Go code the ew.ItemCRUD interface has to be explicitly set with a pointer to an ElfWorker.



The elf knows how to createItem(), which in his case happens to be Toy object. Other workers would implement their own ItemCRUD for their data objects.



type Item interface {                         
// various methods
}
type ItemCRUD interface {
create() Item
// other CRUD
}

type Worker struct {
ItemCRUD // embedded interface
}
func (w *Worker) doWork() {
item := w.create()
// do stuff with item
}

type Toy struct {
}

type ElfWorker struct {
Worker // embedded
// ..
}

func NewElfWorker() *ElfWorker {
ew := &ElfWorker{}
ew.ItemCRUD = ew // <-- #### set Worker ItemCRUD explicitly ####
return ew
}

func (ew *ElfWorker) createItem() Item {
return &Toy{}
}
// more ElfWorker Item CRUD
func bigFunction(w *Worker) {
// ...
w.doWork()
// ..
}


So the part that I am wrestling a bit with is explicit setting. Seems like the "Go way" of composition does require this explicit step if I want the base Worker class to provide shared methods on Items.



Thoughts?










share|improve this question




















  • 7





    Drawing parallels between C++ and any other language can prove to be counter-productive.

    – Ron
    Jan 2 at 18:30











  • first derivative to @Ron’s comment: Applying patterns found in other programming languages to Go can prove counter-productive.

    – Markus W Mahlberg
    Jan 2 at 23:43











  • I'm voting to close this question as off-topic because it shouldbe moved to Codereview

    – thst
    Jan 3 at 8:11











  • Down vote because I asked for feedback on a design choice? I think I clearly stated I was looking to learn? I stated up front the languages would solve the problem in different ways.

    – meissnersd
    Jan 3 at 19:24














-4












-4








-4








I am still learning the Go way of doing things, coming from a C++ background. I am looking for feedback contrasting OOP inheritance to interface composition.



I have a design situation in a Go program where, if I was implementing in C++, I would solve with an abstract base class.



Suppose I need a base class, which has many implementors. The base class has shared methods that do work on abstract data items. Different Worker implementations provide CRUD operations on different item types, but workers all use the shared methods of the base class for general work.



In C++ I might do it this way



class IItem
{
// virtual methods
};

class IWorker
{
public:
// one of many virtual functions that deal with IItem CRUD
virtual IItem* createItem() = 0;

// concrete method that works on interfaces
void doWork()
{
IItem* item = createItem();
// do stuff with an IItem*
}

};


class Toy : public IItem
{

};

// one of many kinds of workers
class ElfWorker : public IWorker
{
public:

ElfWorker()
{
// constructor implicitly calls IWorker()
}

IItem* createItem() override
{
return new Toy;
}
};


In Go you don't have abstract virtual methods such as IWorker::createItem(). Concrete classes need to supply the base with an interface or function that do the right thing.



So I think it is the case that the Go code the ew.ItemCRUD interface has to be explicitly set with a pointer to an ElfWorker.



The elf knows how to createItem(), which in his case happens to be Toy object. Other workers would implement their own ItemCRUD for their data objects.



type Item interface {                         
// various methods
}
type ItemCRUD interface {
create() Item
// other CRUD
}

type Worker struct {
ItemCRUD // embedded interface
}
func (w *Worker) doWork() {
item := w.create()
// do stuff with item
}

type Toy struct {
}

type ElfWorker struct {
Worker // embedded
// ..
}

func NewElfWorker() *ElfWorker {
ew := &ElfWorker{}
ew.ItemCRUD = ew // <-- #### set Worker ItemCRUD explicitly ####
return ew
}

func (ew *ElfWorker) createItem() Item {
return &Toy{}
}
// more ElfWorker Item CRUD
func bigFunction(w *Worker) {
// ...
w.doWork()
// ..
}


So the part that I am wrestling a bit with is explicit setting. Seems like the "Go way" of composition does require this explicit step if I want the base Worker class to provide shared methods on Items.



Thoughts?










share|improve this question
















I am still learning the Go way of doing things, coming from a C++ background. I am looking for feedback contrasting OOP inheritance to interface composition.



I have a design situation in a Go program where, if I was implementing in C++, I would solve with an abstract base class.



Suppose I need a base class, which has many implementors. The base class has shared methods that do work on abstract data items. Different Worker implementations provide CRUD operations on different item types, but workers all use the shared methods of the base class for general work.



In C++ I might do it this way



class IItem
{
// virtual methods
};

class IWorker
{
public:
// one of many virtual functions that deal with IItem CRUD
virtual IItem* createItem() = 0;

// concrete method that works on interfaces
void doWork()
{
IItem* item = createItem();
// do stuff with an IItem*
}

};


class Toy : public IItem
{

};

// one of many kinds of workers
class ElfWorker : public IWorker
{
public:

ElfWorker()
{
// constructor implicitly calls IWorker()
}

IItem* createItem() override
{
return new Toy;
}
};


In Go you don't have abstract virtual methods such as IWorker::createItem(). Concrete classes need to supply the base with an interface or function that do the right thing.



So I think it is the case that the Go code the ew.ItemCRUD interface has to be explicitly set with a pointer to an ElfWorker.



The elf knows how to createItem(), which in his case happens to be Toy object. Other workers would implement their own ItemCRUD for their data objects.



type Item interface {                         
// various methods
}
type ItemCRUD interface {
create() Item
// other CRUD
}

type Worker struct {
ItemCRUD // embedded interface
}
func (w *Worker) doWork() {
item := w.create()
// do stuff with item
}

type Toy struct {
}

type ElfWorker struct {
Worker // embedded
// ..
}

func NewElfWorker() *ElfWorker {
ew := &ElfWorker{}
ew.ItemCRUD = ew // <-- #### set Worker ItemCRUD explicitly ####
return ew
}

func (ew *ElfWorker) createItem() Item {
return &Toy{}
}
// more ElfWorker Item CRUD
func bigFunction(w *Worker) {
// ...
w.doWork()
// ..
}


So the part that I am wrestling a bit with is explicit setting. Seems like the "Go way" of composition does require this explicit step if I want the base Worker class to provide shared methods on Items.



Thoughts?







go virtual composition






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Jan 2 at 19:38









Flimzy

40.2k1367100




40.2k1367100










asked Jan 2 at 18:28









meissnersdmeissnersd

7261818




7261818








  • 7





    Drawing parallels between C++ and any other language can prove to be counter-productive.

    – Ron
    Jan 2 at 18:30











  • first derivative to @Ron’s comment: Applying patterns found in other programming languages to Go can prove counter-productive.

    – Markus W Mahlberg
    Jan 2 at 23:43











  • I'm voting to close this question as off-topic because it shouldbe moved to Codereview

    – thst
    Jan 3 at 8:11











  • Down vote because I asked for feedback on a design choice? I think I clearly stated I was looking to learn? I stated up front the languages would solve the problem in different ways.

    – meissnersd
    Jan 3 at 19:24














  • 7





    Drawing parallels between C++ and any other language can prove to be counter-productive.

    – Ron
    Jan 2 at 18:30











  • first derivative to @Ron’s comment: Applying patterns found in other programming languages to Go can prove counter-productive.

    – Markus W Mahlberg
    Jan 2 at 23:43











  • I'm voting to close this question as off-topic because it shouldbe moved to Codereview

    – thst
    Jan 3 at 8:11











  • Down vote because I asked for feedback on a design choice? I think I clearly stated I was looking to learn? I stated up front the languages would solve the problem in different ways.

    – meissnersd
    Jan 3 at 19:24








7




7





Drawing parallels between C++ and any other language can prove to be counter-productive.

– Ron
Jan 2 at 18:30





Drawing parallels between C++ and any other language can prove to be counter-productive.

– Ron
Jan 2 at 18:30













first derivative to @Ron’s comment: Applying patterns found in other programming languages to Go can prove counter-productive.

– Markus W Mahlberg
Jan 2 at 23:43





first derivative to @Ron’s comment: Applying patterns found in other programming languages to Go can prove counter-productive.

– Markus W Mahlberg
Jan 2 at 23:43













I'm voting to close this question as off-topic because it shouldbe moved to Codereview

– thst
Jan 3 at 8:11





I'm voting to close this question as off-topic because it shouldbe moved to Codereview

– thst
Jan 3 at 8:11













Down vote because I asked for feedback on a design choice? I think I clearly stated I was looking to learn? I stated up front the languages would solve the problem in different ways.

– meissnersd
Jan 3 at 19:24





Down vote because I asked for feedback on a design choice? I think I clearly stated I was looking to learn? I stated up front the languages would solve the problem in different ways.

– meissnersd
Jan 3 at 19:24












2 Answers
2






active

oldest

votes


















0














Beeing new to go myself, this answer is not backed by years of go experience :-)



I don't know, if the way you tackle this is the correct approach.
go allows interfaces to be implemented without explicit declaration. If you have elves, and you need them to do ItemCRUD methods, just implement them.



The method set will then match the interface and you can use the elf as a ItemCRUD where required.



To supply any elf object with a default ItemCRUD Implementation, you should implement an adapter for the ItemCRUD and compose the adapter with your abstract elf. The abstract methods could have a default implementation as log.Fatal("not implemented")



The concrete elves shadow the adapter's methods, this answers your question: It is not required to insert the object during creation.



Yet, since go has no generics, it may not be the right approach to have an ItemCRUD.






share|improve this answer

































    0














    Im not entirely clear what the plan is with the above code and without understanding that its hard to suggest specific solutions, what is clear is you are very much coming to the party with an established OOP mindset (I did too) which is rarely helpful in finding the best solution in golang.



    In Golang I wouldnt usually embed an interface in an implementation, interfaces are satisfied implicitly in Golang which allows for a nice separation of expectation and implementation which should generally be respected.
    A reciever method should expect an interface, the implementation passed at runtime should just satisfy the signature of that interface implicitly.



    So perhaps my doWork method needs to be able to createItems then it would be the doWork method that would accept any implementation of ItemCRUD which it could call to create an item. But this is me guessing at what you really want to do here, I suspect if you just separate implementation from interface you will probably answer your own question.






    share|improve this answer
























      Your Answer






      StackExchange.ifUsing("editor", function () {
      StackExchange.using("externalEditor", function () {
      StackExchange.using("snippets", function () {
      StackExchange.snippets.init();
      });
      });
      }, "code-snippets");

      StackExchange.ready(function() {
      var channelOptions = {
      tags: "".split(" "),
      id: "1"
      };
      initTagRenderer("".split(" "), "".split(" "), channelOptions);

      StackExchange.using("externalEditor", function() {
      // Have to fire editor after snippets, if snippets enabled
      if (StackExchange.settings.snippets.snippetsEnabled) {
      StackExchange.using("snippets", function() {
      createEditor();
      });
      }
      else {
      createEditor();
      }
      });

      function createEditor() {
      StackExchange.prepareEditor({
      heartbeatType: 'answer',
      autoActivateHeartbeat: false,
      convertImagesToLinks: true,
      noModals: true,
      showLowRepImageUploadWarning: true,
      reputationToPostImages: 10,
      bindNavPrevention: true,
      postfix: "",
      imageUploader: {
      brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
      contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
      allowUrls: true
      },
      onDemand: true,
      discardSelector: ".discard-answer"
      ,immediatelyShowMarkdownHelp:true
      });


      }
      });














      draft saved

      draft discarded


















      StackExchange.ready(
      function () {
      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54011364%2fabstract-base-class-design-in-go-vs-c%23new-answer', 'question_page');
      }
      );

      Post as a guest















      Required, but never shown

























      2 Answers
      2






      active

      oldest

      votes








      2 Answers
      2






      active

      oldest

      votes









      active

      oldest

      votes






      active

      oldest

      votes









      0














      Beeing new to go myself, this answer is not backed by years of go experience :-)



      I don't know, if the way you tackle this is the correct approach.
      go allows interfaces to be implemented without explicit declaration. If you have elves, and you need them to do ItemCRUD methods, just implement them.



      The method set will then match the interface and you can use the elf as a ItemCRUD where required.



      To supply any elf object with a default ItemCRUD Implementation, you should implement an adapter for the ItemCRUD and compose the adapter with your abstract elf. The abstract methods could have a default implementation as log.Fatal("not implemented")



      The concrete elves shadow the adapter's methods, this answers your question: It is not required to insert the object during creation.



      Yet, since go has no generics, it may not be the right approach to have an ItemCRUD.






      share|improve this answer






























        0














        Beeing new to go myself, this answer is not backed by years of go experience :-)



        I don't know, if the way you tackle this is the correct approach.
        go allows interfaces to be implemented without explicit declaration. If you have elves, and you need them to do ItemCRUD methods, just implement them.



        The method set will then match the interface and you can use the elf as a ItemCRUD where required.



        To supply any elf object with a default ItemCRUD Implementation, you should implement an adapter for the ItemCRUD and compose the adapter with your abstract elf. The abstract methods could have a default implementation as log.Fatal("not implemented")



        The concrete elves shadow the adapter's methods, this answers your question: It is not required to insert the object during creation.



        Yet, since go has no generics, it may not be the right approach to have an ItemCRUD.






        share|improve this answer




























          0












          0








          0







          Beeing new to go myself, this answer is not backed by years of go experience :-)



          I don't know, if the way you tackle this is the correct approach.
          go allows interfaces to be implemented without explicit declaration. If you have elves, and you need them to do ItemCRUD methods, just implement them.



          The method set will then match the interface and you can use the elf as a ItemCRUD where required.



          To supply any elf object with a default ItemCRUD Implementation, you should implement an adapter for the ItemCRUD and compose the adapter with your abstract elf. The abstract methods could have a default implementation as log.Fatal("not implemented")



          The concrete elves shadow the adapter's methods, this answers your question: It is not required to insert the object during creation.



          Yet, since go has no generics, it may not be the right approach to have an ItemCRUD.






          share|improve this answer















          Beeing new to go myself, this answer is not backed by years of go experience :-)



          I don't know, if the way you tackle this is the correct approach.
          go allows interfaces to be implemented without explicit declaration. If you have elves, and you need them to do ItemCRUD methods, just implement them.



          The method set will then match the interface and you can use the elf as a ItemCRUD where required.



          To supply any elf object with a default ItemCRUD Implementation, you should implement an adapter for the ItemCRUD and compose the adapter with your abstract elf. The abstract methods could have a default implementation as log.Fatal("not implemented")



          The concrete elves shadow the adapter's methods, this answers your question: It is not required to insert the object during creation.



          Yet, since go has no generics, it may not be the right approach to have an ItemCRUD.







          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited Jan 2 at 19:00

























          answered Jan 2 at 18:53









          thstthst

          3,70611634




          3,70611634

























              0














              Im not entirely clear what the plan is with the above code and without understanding that its hard to suggest specific solutions, what is clear is you are very much coming to the party with an established OOP mindset (I did too) which is rarely helpful in finding the best solution in golang.



              In Golang I wouldnt usually embed an interface in an implementation, interfaces are satisfied implicitly in Golang which allows for a nice separation of expectation and implementation which should generally be respected.
              A reciever method should expect an interface, the implementation passed at runtime should just satisfy the signature of that interface implicitly.



              So perhaps my doWork method needs to be able to createItems then it would be the doWork method that would accept any implementation of ItemCRUD which it could call to create an item. But this is me guessing at what you really want to do here, I suspect if you just separate implementation from interface you will probably answer your own question.






              share|improve this answer




























                0














                Im not entirely clear what the plan is with the above code and without understanding that its hard to suggest specific solutions, what is clear is you are very much coming to the party with an established OOP mindset (I did too) which is rarely helpful in finding the best solution in golang.



                In Golang I wouldnt usually embed an interface in an implementation, interfaces are satisfied implicitly in Golang which allows for a nice separation of expectation and implementation which should generally be respected.
                A reciever method should expect an interface, the implementation passed at runtime should just satisfy the signature of that interface implicitly.



                So perhaps my doWork method needs to be able to createItems then it would be the doWork method that would accept any implementation of ItemCRUD which it could call to create an item. But this is me guessing at what you really want to do here, I suspect if you just separate implementation from interface you will probably answer your own question.






                share|improve this answer


























                  0












                  0








                  0







                  Im not entirely clear what the plan is with the above code and without understanding that its hard to suggest specific solutions, what is clear is you are very much coming to the party with an established OOP mindset (I did too) which is rarely helpful in finding the best solution in golang.



                  In Golang I wouldnt usually embed an interface in an implementation, interfaces are satisfied implicitly in Golang which allows for a nice separation of expectation and implementation which should generally be respected.
                  A reciever method should expect an interface, the implementation passed at runtime should just satisfy the signature of that interface implicitly.



                  So perhaps my doWork method needs to be able to createItems then it would be the doWork method that would accept any implementation of ItemCRUD which it could call to create an item. But this is me guessing at what you really want to do here, I suspect if you just separate implementation from interface you will probably answer your own question.






                  share|improve this answer













                  Im not entirely clear what the plan is with the above code and without understanding that its hard to suggest specific solutions, what is clear is you are very much coming to the party with an established OOP mindset (I did too) which is rarely helpful in finding the best solution in golang.



                  In Golang I wouldnt usually embed an interface in an implementation, interfaces are satisfied implicitly in Golang which allows for a nice separation of expectation and implementation which should generally be respected.
                  A reciever method should expect an interface, the implementation passed at runtime should just satisfy the signature of that interface implicitly.



                  So perhaps my doWork method needs to be able to createItems then it would be the doWork method that would accept any implementation of ItemCRUD which it could call to create an item. But this is me guessing at what you really want to do here, I suspect if you just separate implementation from interface you will probably answer your own question.







                  share|improve this answer












                  share|improve this answer



                  share|improve this answer










                  answered Jan 2 at 19:03









                  SwiftDSwiftD

                  3,35642753




                  3,35642753






























                      draft saved

                      draft discarded




















































                      Thanks for contributing an answer to Stack Overflow!


                      • Please be sure to answer the question. Provide details and share your research!

                      But avoid



                      • Asking for help, clarification, or responding to other answers.

                      • Making statements based on opinion; back them up with references or personal experience.


                      To learn more, see our tips on writing great answers.




                      draft saved


                      draft discarded














                      StackExchange.ready(
                      function () {
                      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54011364%2fabstract-base-class-design-in-go-vs-c%23new-answer', 'question_page');
                      }
                      );

                      Post as a guest















                      Required, but never shown





















































                      Required, but never shown














                      Required, but never shown












                      Required, but never shown







                      Required, but never shown

































                      Required, but never shown














                      Required, but never shown












                      Required, but never shown







                      Required, but never shown







                      Popular posts from this blog

                      MongoDB - Not Authorized To Execute Command

                      in spring boot 2.1 many test slices are not allowed anymore due to multiple @BootstrapWith

                      How to fix TextFormField cause rebuild widget in Flutter