FAQ
Go lacks the sense of inheritance of C#, Java, C++. I wonder what is the
right idiom to model this use case:

struct Envelope {
Code int
Payload interface{}
}

struct MyActualPayloadA {
Some string
Another int
}

struct MyActualPayloadB {
Herecomes []int
Yousee float
}

return := &Envelope{Code: 5, Payload: &MyActualPayloadA{}}

This works of course, but is it the right way of doing or would an
interface type help here not to (ab-) use the catch-all interface{} ?

(In a C++ ish world I would define a Payload class, derive MayActual..A / B
from that and use Payload as the member type in Envelope)

Regards, Johann

--

Search Discussions

  • Taru Karttunen at Nov 8, 2012 at 9:31 am

    On Thu, 8 Nov 2012 01:06:12 -0800 (PST), "=?UTF-8?Q?Johann_H=C3=B6chtl?=" wrote:
    Go lacks the sense of inheritance of C#, Java, C++. I wonder what is the
    right idiom to model this use case:
    struct Common {
    Code int
    }

    struct MyActualPayloadA {
    Common
    Some string
    Another int
    }

    struct MyActualPayloadB {
    Common
    Herecomes []int
    Yousee float
    }

    If one needs polymorphism then one can use interfaces.

    - Taru Karttunen

    --
  • Kevin Gillette at Nov 8, 2012 at 9:33 am

    On Thursday, November 8, 2012 2:31:53 AM UTC-7, Taru Karttunen wrote:
    If one needs polymorphism then one can use interfaces.
    Yes -- non-empty interfaces.

    --
  • Johann Höchtl at Nov 8, 2012 at 9:34 am

    On 08.11.2012 10:32, Taru Karttunen wrote:
    On Thu, 8 Nov 2012 01:06:12 -0800 (PST), "=?UTF-8?Q?Johann_H=C3=B6chtl?=" wrote:
    Go lacks the sense of inheritance of C#, Java, C++. I wonder what is the
    right idiom to model this use case:
    struct Common {
    Code int
    }

    struct MyActualPayloadA {
    Common
    Some string
    Another int
    }

    struct MyActualPayloadB {
    Common
    Herecomes []int
    Yousee float
    }

    If one needs polymorphism then one can use interfaces.
    This makes MyActualPayloadA/B the top level type, whereas it should be
    Common. Not the intention of the interface I have in mind
    - Taru Karttunen
    --
  • Jesse McNelis at Nov 8, 2012 at 9:49 am

    On Thu, Nov 8, 2012 at 8:33 PM, Johann Höchtl wrote:

    This makes MyActualPayloadA/B the top level type, whereas it should be
    Common. Not the intention of the interface I have in mind
    Since you described a problem that is only solvable using inheritance then
    you need inheritance.
    If you provide the more general problem that you're trying to solve then
    it's possible to provide non-inheritance based solutions.

    Why does Envelope need to be the 'top level type'? What are you doing with
    this collection of Envelopes?
    What is common between MyActualPayloadA and MyActualPayloadB? Is it just
    the fields in Envelope? or is it some kind of behaviour?


    --
    =====================
    http://jessta.id.au

    --
  • Johann Höchtl at Nov 8, 2012 at 10:18 am

    On 08.11.2012 10:49, Jesse McNelis wrote:
    On Thu, Nov 8, 2012 at 8:33 PM, Johann Höchtl
    wrote:

    This makes MyActualPayloadA/B the top level type, whereas it
    should be Common. Not the intention of the interface I have in mind


    Since you described a problem that is only solvable using inheritance
    then you need inheritance.
    If you provide the more general problem that you're trying to solve
    then it's possible to provide non-inheritance based solutions.

    Why does Envelope need to be the 'top level type'? What are you doing
    with this collection of Envelopes?
    What is common between MyActualPayloadA and MyActualPayloadB? Is it
    just the fields in Envelope? or is it some kind of behaviour?
    Use-case is as follows:

    User makes a request to a JSON-API, the API does some conversion based
    on methods and parameters (obviously). The result will be an envelope
    which contains a Status message, a Boolean error flag, Processing Code
    and the call parameters. This type of information is invariant.
    And then there is method-specific response, which I intend to embed into
    the envelope as Payload. The caller can deal with the response:

    1. first parse the envelope which is commonly understood by the incoming
    filter. In case of no error -->
    2. the payload is parsed by the requesting routine which understands the
    structure of payload.

    Having the gatekeeper parsing the envelope for generic errors makes the
    envelope type encompasing the payload reasonable IMHO.

    Note: I have the code working using interface{} here,
    https://github.com/the42/cartconvert/blob/master/cartconvserv/cartconvserv.go
    I just wonder if it's more 'idiomatically' doable otherwise.
    --
    =====================
    http://jessta.id.au
    --
  • Saul Hazledine at Nov 9, 2012 at 7:32 am
    Hello,
    On Thursday, 8 November 2012 11:19:00 UTC+1, Johann Höchtl wrote:

    Use-case is as follows:

    User makes a request to a JSON-API, the API does some conversion based on
    methods and parameters (obviously). The result will be an envelope which
    contains a Status message, a Boolean error flag, Processing Code and the
    call parameters. This type of information is invariant.
    And then there is method-specific response, which I intend to embed into
    the envelope as Payload. The caller can deal with the response:

    1. first parse the envelope which is commonly understood by the incoming
    filter. In case of no error -->
    2. the payload is parsed by the requesting routine which understands the
    structure of payload.

    This seems to be a description of a polymorphic JSON API. In Java its
    possible to write such an API using inheritance as you described earlier in
    this thread. I've seen Go code that does polymorphism with XML:

    https://github.com/mattn/go-xmpp/blob/master/xmpp.go#L385

    However, the JSON package is structured differently. One way around this,
    that I haven't tried, would be to read JSON values into a map using:

    var envelope interface{}
    err := json.Unmarshal(b, &envelope)

    Doing standard checks on the envelope map and then doing some reflection to
    convert the payload map into a struct, or writing a "constructor" for each
    payload type that takes a map.

    Saul

    --
  • Thomas Kappler at Nov 8, 2012 at 10:54 am

    On Thursday, November 8, 2012 10:34:23 AM UTC+1, Johann Höchtl wrote:
    On 08.11.2012 10:32, Taru Karttunen wrote:
    On Thu, 8 Nov 2012 01:06:12 -0800 (PST),
    "=?UTF-8?Q?Johann_H=C3=B6chtl?=" <johann....@gmail.com <javascript:>>
    wrote:
    Go lacks the sense of inheritance of C#, Java, C++. I wonder what is
    the
    right idiom to model this use case:
    struct Common {
    Code int
    }

    struct MyActualPayloadA {
    Common
    Some string
    Another int
    }

    struct MyActualPayloadB [...]

    If one needs polymorphism then one can use interfaces.
    This makes MyActualPayloadA/B the top level type, whereas it should be
    Common. Not the intention of the interface I have in mind
    The notion of a top-level type doesn't really make sense without
    inheritance. What's the problem with Common not being special? I think
    Taru's solution is concise and readable.

    Thomas

    --
  • Glenn Brown at Nov 8, 2012 at 7:21 pm

    Go lacks the sense of inheritance of C#, Java, C++. I wonder what is the right idiom to model this use case:

    struct Envelope {
    Code int
    Payload interface{}
    } ...
    (In a C++ ish world I would define a Payload class, derive MayActual..A / B from that and use Payload as the member type in Envelope)
    In Go, you can use the C++ approach, but it is simpler: the types implementing the interface don't need to mention the interface.
    I put the following runnable example at http://play.golang.org/p/TAeqtY0P3G .

    --Glenn

    package main

    import "fmt"

    // Define the envelope type.
    type Envelope struct {
    Code int
    Payload interface {
    String() string
    }
    }

    func (e Envelope) String() string {
    return fmt.Sprint("Envelope:{Code:", e.Code, " Payload:", e.Payload.String(), "}")
    }

    // Define a type that incidentally implements the Payload interface.
    // This need not be in the same package as the interface definition. Note that
    // these do NOT need to mention "interface" at all, but they do implement all functions in the
    // Payload interface.

    type Type1 struct {
    f float64
    }

    func (t Type1) String() string {
    return fmt.Sprint("Type1:{f:", t.f, "}")
    }

    // Define another type that implements Payload:

    type Type2 struct {
    i int
    }

    func (t Type2) String() string {
    return fmt.Sprint("Type2:{i:", t.i, "}")
    }

    // Create and print a couple of Envelopes, each with a different type Payload:
    //
    func main() {
    fmt.Println(Envelope{1, &Type1{1.1}}, Envelope{2, &Type2{1}})
    // Output: Envelope:{Code:1 Payload:Type1:{f:1.1}} Envelope:{Code:2 Payload:Type2:{i:1}}
    }

    --
  • Johann Höchtl at Nov 10, 2012 at 11:20 am

    On 08.11.2012 20:21, Glenn Brown wrote:
    Go lacks the sense of inheritance of C#, Java, C++. I wonder what is the right idiom to model this use case:

    struct Envelope {
    Code int
    Payload interface{}
    }
    ...
    Based on your answer, I think the way to go for me is indeed using
    interface{}

    Embeding the other way round, as some suggested, would help to retain
    some sort of type information, yet elide the functionality of a top
    level Envelope, which I think Is reasonable as I am serialising to JSON
    or XML.

    Thank you, Johann
    (In a C++ ish world I would define a Payload class, derive MayActual..A / B from that and use Payload as the member type in Envelope)
    In Go, you can use the C++ approach, but it is simpler: the types implementing the interface don't need to mention the interface.
    I put the following runnable example at http://play.golang.org/p/TAeqtY0P3G .

    --Glenn

    package main

    import "fmt"

    // Define the envelope type.
    type Envelope struct {
    Code int
    Payload interface {
    String() string
    }
    }

    func (e Envelope) String() string {
    return fmt.Sprint("Envelope:{Code:", e.Code, " Payload:", e.Payload.String(), "}")
    }

    // Define a type that incidentally implements the Payload interface.
    // This need not be in the same package as the interface definition. Note that
    // these do NOT need to mention "interface" at all, but they do implement all functions in the
    // Payload interface.

    type Type1 struct {
    f float64
    }

    func (t Type1) String() string {
    return fmt.Sprint("Type1:{f:", t.f, "}")
    }

    // Define another type that implements Payload:

    type Type2 struct {
    i int
    }

    func (t Type2) String() string {
    return fmt.Sprint("Type2:{i:", t.i, "}")
    }

    // Create and print a couple of Envelopes, each with a different type Payload:
    //
    func main() {
    fmt.Println(Envelope{1, &Type1{1.1}}, Envelope{2, &Type2{1}})
    // Output: Envelope:{Code:1 Payload:Type1:{f:1.1}} Envelope:{Code:2 Payload:Type2:{i:1}}
    }
    --

Related Discussions

Discussion Navigation
viewthread | post
Discussion Overview
groupgolang-nuts @
categoriesgo
postedNov 8, '12 at 9:06a
activeNov 10, '12 at 11:20a
posts10
users7
websitegolang.org

People

Translate

site design / logo © 2021 Grokbase