FAQ
I've been unable to find a way to use functions returning things of various
types that implement an interface, in a place where I'm using the interface
as a type to group them together. I've cut my program down to demonstrate
the effect, and explained it inline in the code (also available at
http://play.golang.org/p/_TGARDvBSF ). The nearest post I can find in the
archives is
https://groups.google.com/forum/#!searchin/golang-nuts/convert$20function$20interface/golang-nuts/awwdsmqTRNA/LkOMmxjsHakJ
but I don't think it's quite the same problem. For the problem
description, look for "If I uncomment these" in the code below:

// Program demonstrating a problem I'm having with trying to cast /
// convert functions returning various types that implement an
// interface, to a type that specifies that interface

package main

import "fmt"

// real job dispatch

type SshJob struct {
     host string
     command string
}

func BuildSshJob(host, command string) SshJob {
     return SshJob {
         host: host,
         command: command,
     }
}

func (j SshJob)StartJob() {
     fmt.Printf("Starting job \"%s\" on %s via SSH\n", j.command, j.host)
}

// dummy job dispatch

type DummyJob struct {
     host string
     command string
}

func BuildDummyJob(host, command string) DummyJob {
     return DummyJob {
         host: host,
         command: command,
     }
}

func (j DummyJob)StartJob() {
     fmt.Printf("Pretending to start job \"%s\" on %s\n", j.command, j.host)
}

// Common interface to real and dummy jobs

type UnderlyingJob interface {
     StartJob()
}

type UnderlyingJobCreatorFunc func(host string, command string)
UnderlyingJob

// some wrappers, because I can't get it to work without them

func BuildSshJob_wrapper(host, command string) UnderlyingJob {
     return BuildSshJob(host, command)
}

func BuildDummyJob_wrapper (host, command string) UnderlyingJob {
     return BuildDummyJob(host, command)
}

// map from type name to function to create appropriate structure

var UnderlyingJobCreators = map[string]UnderlyingJobCreatorFunc {

     // A work-round, but not what I really wanted:

     "wrapped_dummy": BuildDummyJob_wrapper,
     "wrapped_real": BuildSshJob_wrapper,

     // These two are how I really wanted to do this, but they
     // won't compile; I can create wrapper functions which do the
     // conversion dynamically, but the language doesn't let me do
     // the conversion statically here.

     // If I uncomment these, I get:
     // ./fif.go:81: cannot convert BuildDummyJob (type func(string, string)
DummyJob) to type UnderlyingJobCreatorFunc
     // ./fif.go:82: cannot convert BuildSshJob (type func(string, string)
SshJob) to type UnderlyingJobCreatorFunc

     // "dummy": UnderlyingJobCreatorFunc(BuildDummyJob),
     // "real": UnderlyingJobCreatorFunc(BuildSshJob),
}

func BuildUnderlyingJob(jobtype string, host string, command string)
UnderlyingJob {
     return UnderlyingJobCreators[jobtype](host, command)
}

// program using either type of job

func main() {
     fmt.Println("hello")
     dryrunner_0 := BuildDummyJob("localhost", "echo Hello Dummy")
     dryrunner_0.StartJob()
     runner_0 := BuildSshJob("localhost", "echo Hello network")
     runner_0.StartJob()

     dryrunner_1 := BuildUnderlyingJob("wrapped_dummy", "localhost", "echo
Hello Dummy")
     dryrunner_1.StartJob()
     runner_1 := BuildUnderlyingJob("wrapped_real", "localhost", "echo Hello
network")
     runner_1.StartJob()
}

I'm new to Go (my background is Lisp, C, and Python), but I've asked
colleagues who're more experienced in Go, and they reckon this should be
possible, but they can't see how, either.

__John

--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Search Discussions

  • Jan Mercl at Jul 10, 2014 at 11:40 am
    On Thu, Jul 10, 2014 at 1:02 PM, wrote:

    No conversion can change the signature of a function in such a way
    where the original result type becomes any other type.

    -j

    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
  • Jcg Sturdy at Jul 10, 2014 at 11:55 am

    On Thursday, July 10, 2014 12:40:24 PM UTC+1, Jan Mercl wrote:
    On Thu, Jul 10, 2014 at 1:02 PM, <jcg.s...@gmail.com <javascript:>>
    wrote:

    No conversion can change the signature of a function in such a way
    where the original result type becomes any other type.
    This seems inconsistent to me; it's allowed me to do the conversions in the
    functions BuildSshJob_wrapper and BuildDummyJob_wrapper, so I had hoped it
    would be possible to do the conversion statically with the casts in that
    map definition.

    Also, the conversion (either the static ones in the map, or the dynamic
    ones in those wrapper functions) are both generalizations rather than
    specializations. I thought the problem was probably something to do with
    that I'm trying to convert to an interface type from a non-interface type
    (which can be seen to implement that interface). But I can't find a syntax
    that gets round this.

    Thanks for the quick reply!

    __John

    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
  • Jan Mercl at Jul 10, 2014 at 12:26 pm

    On Thu, Jul 10, 2014 at 1:54 PM, wrote:
    On Thursday, July 10, 2014 12:40:24 PM UTC+1, Jan Mercl wrote:

    On Thu, Jul 10, 2014 at 1:02 PM, wrote:

    No conversion can change the signature of a function in such a way
    where the original result type becomes any other type.

    This seems inconsistent to me;
    The consistency is in that no conversion of T can produce U such that
    T is not assignable to U b/c that would render type safety useless.
    (Modulo "unsafe" and special rules for numbers and strings.)
    it's allowed me to do the conversions in the
    functions BuildSshJob_wrapper
    That's not a conversion of a function and not even a conversion but an
    assignment. Expression of type T satisfying interface I is always
    assignable to an I typed value.

    -j

    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
  • Jcg Sturdy at Jul 10, 2014 at 12:53 pm

    On Thursday, July 10, 2014 1:27:08 PM UTC+1, Jan Mercl wrote:

    That's not a conversion of a function and not even a conversion but an
    assignment. Expression of type T satisfying interface I is always
    assignable to an I typed value.
    Yes, I think I see the difference. I had been thinking of it as assigning
    the result of a conversion, rather than assignment being able to do a more
    powerful implicit conversion.

    Thanks!

    __John

    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
  • Tomwilde at Jul 10, 2014 at 11:50 am
    You used "BuildDummyJob_wrapper", I suggest you simply use lambdas of the
    correct type:

    "dummy": func(host, command string) UnderlyingJob {
         return UnderlyingJob(BuildDummyJob(host, command))
    }
    On Thursday, July 10, 2014 1:02:20 PM UTC+2, jcg.s...@gmail.com wrote:

    I've been unable to find a way to use functions returning things of
    various types that implement an interface, in a place where I'm using the
    interface as a type to group them together. I've cut my program down to
    demonstrate the effect, and explained it inline in the code (also available
    at http://play.golang.org/p/_TGARDvBSF ). The nearest post I can find in
    the archives is
    https://groups.google.com/forum/#!searchin/golang-nuts/convert$20function$20interface/golang-nuts/awwdsmqTRNA/LkOMmxjsHakJ
    but I don't think it's quite the same problem. For the problem
    description, look for "If I uncomment these" in the code below:

    // Program demonstrating a problem I'm having with trying to cast /
    // convert functions returning various types that implement an
    // interface, to a type that specifies that interface

    package main

    import "fmt"

    // real job dispatch

    type SshJob struct {
    host string
    command string
    }

    func BuildSshJob(host, command string) SshJob {
    return SshJob {
    host: host,
    command: command,
    }
    }

    func (j SshJob)StartJob() {
    fmt.Printf("Starting job \"%s\" on %s via SSH\n", j.command, j.host)
    }

    // dummy job dispatch

    type DummyJob struct {
    host string
    command string
    }

    func BuildDummyJob(host, command string) DummyJob {
    return DummyJob {
    host: host,
    command: command,
    }
    }

    func (j DummyJob)StartJob() {
    fmt.Printf("Pretending to start job \"%s\" on %s\n", j.command, j.host)
    }

    // Common interface to real and dummy jobs

    type UnderlyingJob interface {
    StartJob()
    }

    type UnderlyingJobCreatorFunc func(host string, command string)
    UnderlyingJob

    // some wrappers, because I can't get it to work without them

    func BuildSshJob_wrapper(host, command string) UnderlyingJob {
    return BuildSshJob(host, command)
    }

    func BuildDummyJob_wrapper (host, command string) UnderlyingJob {
    return BuildDummyJob(host, command)
    }

    // map from type name to function to create appropriate structure

    var UnderlyingJobCreators = map[string]UnderlyingJobCreatorFunc {

    // A work-round, but not what I really wanted:

    "wrapped_dummy": BuildDummyJob_wrapper,
    "wrapped_real": BuildSshJob_wrapper,

    // These two are how I really wanted to do this, but they
    // won't compile; I can create wrapper functions which do the
    // conversion dynamically, but the language doesn't let me do
    // the conversion statically here.

    // If I uncomment these, I get:
    // ./fif.go:81: cannot convert BuildDummyJob (type func(string,
    string) DummyJob) to type UnderlyingJobCreatorFunc
    // ./fif.go:82: cannot convert BuildSshJob (type func(string, string)
    SshJob) to type UnderlyingJobCreatorFunc

    // "dummy": UnderlyingJobCreatorFunc(BuildDummyJob),
    // "real": UnderlyingJobCreatorFunc(BuildSshJob),
    }

    func BuildUnderlyingJob(jobtype string, host string, command string)
    UnderlyingJob {
    return UnderlyingJobCreators[jobtype](host, command)
    }

    // program using either type of job

    func main() {
    fmt.Println("hello")
    dryrunner_0 := BuildDummyJob("localhost", "echo Hello Dummy")
    dryrunner_0.StartJob()
    runner_0 := BuildSshJob("localhost", "echo Hello network")
    runner_0.StartJob()

    dryrunner_1 := BuildUnderlyingJob("wrapped_dummy", "localhost", "echo
    Hello Dummy")
    dryrunner_1.StartJob()
    runner_1 := BuildUnderlyingJob("wrapped_real", "localhost", "echo
    Hello network")
    runner_1.StartJob()
    }

    I'm new to Go (my background is Lisp, C, and Python), but I've asked
    colleagues who're more experienced in Go, and they reckon this should be
    possible, but they can't see how, either.

    __John
    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
  • Jcg Sturdy at Jul 10, 2014 at 12:06 pm

    On Thursday, July 10, 2014 12:50:14 PM UTC+1, tomwilde wrote:
    You used "BuildDummyJob_wrapper", I suggest you simply use lambdas of the
    correct type:

    "dummy": func(host, command string) UnderlyingJob {
    return UnderlyingJob(BuildDummyJob(host, command))
    }
    Yes, that's much neater, thanks. I've haven't yet got used to a
    curly-braces language being civilized enough to do inline lambdas!

    __John


    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
  • Chris Hines at Jul 10, 2014 at 12:38 pm
    Here is an alternate implementation that uses a switch instead of a map. I
    think it is a better approach as long as the mapping is static.

    http://play.golang.org/p/eVkp7O0KzS
    On Thursday, July 10, 2014 7:02:20 AM UTC-4, jcg.s...@gmail.com wrote:

    I've been unable to find a way to use functions returning things of
    various types that implement an interface, in a place where I'm using the
    interface as a type to group them together. I've cut my program down to
    demonstrate the effect, and explained it inline in the code (also available
    at http://play.golang.org/p/_TGARDvBSF ). The nearest post I can find in
    the archives is
    https://groups.google.com/forum/#!searchin/golang-nuts/convert$20function$20interface/golang-nuts/awwdsmqTRNA/LkOMmxjsHakJ
    but I don't think it's quite the same problem. For the problem
    description, look for "If I uncomment these" in the code below:

    // Program demonstrating a problem I'm having with trying to cast /
    // convert functions returning various types that implement an
    // interface, to a type that specifies that interface

    package main

    import "fmt"

    // real job dispatch

    type SshJob struct {
    host string
    command string
    }

    func BuildSshJob(host, command string) SshJob {
    return SshJob {
    host: host,
    command: command,
    }
    }

    func (j SshJob)StartJob() {
    fmt.Printf("Starting job \"%s\" on %s via SSH\n", j.command, j.host)
    }

    // dummy job dispatch

    type DummyJob struct {
    host string
    command string
    }

    func BuildDummyJob(host, command string) DummyJob {
    return DummyJob {
    host: host,
    command: command,
    }
    }

    func (j DummyJob)StartJob() {
    fmt.Printf("Pretending to start job \"%s\" on %s\n", j.command, j.host)
    }

    // Common interface to real and dummy jobs

    type UnderlyingJob interface {
    StartJob()
    }

    type UnderlyingJobCreatorFunc func(host string, command string)
    UnderlyingJob

    // some wrappers, because I can't get it to work without them

    func BuildSshJob_wrapper(host, command string) UnderlyingJob {
    return BuildSshJob(host, command)
    }

    func BuildDummyJob_wrapper (host, command string) UnderlyingJob {
    return BuildDummyJob(host, command)
    }

    // map from type name to function to create appropriate structure

    var UnderlyingJobCreators = map[string]UnderlyingJobCreatorFunc {

    // A work-round, but not what I really wanted:

    "wrapped_dummy": BuildDummyJob_wrapper,
    "wrapped_real": BuildSshJob_wrapper,

    // These two are how I really wanted to do this, but they
    // won't compile; I can create wrapper functions which do the
    // conversion dynamically, but the language doesn't let me do
    // the conversion statically here.

    // If I uncomment these, I get:
    // ./fif.go:81: cannot convert BuildDummyJob (type func(string,
    string) DummyJob) to type UnderlyingJobCreatorFunc
    // ./fif.go:82: cannot convert BuildSshJob (type func(string, string)
    SshJob) to type UnderlyingJobCreatorFunc

    // "dummy": UnderlyingJobCreatorFunc(BuildDummyJob),
    // "real": UnderlyingJobCreatorFunc(BuildSshJob),
    }

    func BuildUnderlyingJob(jobtype string, host string, command string)
    UnderlyingJob {
    return UnderlyingJobCreators[jobtype](host, command)
    }

    // program using either type of job

    func main() {
    fmt.Println("hello")
    dryrunner_0 := BuildDummyJob("localhost", "echo Hello Dummy")
    dryrunner_0.StartJob()
    runner_0 := BuildSshJob("localhost", "echo Hello network")
    runner_0.StartJob()

    dryrunner_1 := BuildUnderlyingJob("wrapped_dummy", "localhost", "echo
    Hello Dummy")
    dryrunner_1.StartJob()
    runner_1 := BuildUnderlyingJob("wrapped_real", "localhost", "echo
    Hello network")
    runner_1.StartJob()
    }

    I'm new to Go (my background is Lisp, C, and Python), but I've asked
    colleagues who're more experienced in Go, and they reckon this should be
    possible, but they can't see how, either.

    __John
    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
  • Jcg Sturdy at Jul 10, 2014 at 12:56 pm

    On Thursday, July 10, 2014 1:37:56 PM UTC+1, Chris Hines wrote:
    Here is an alternate implementation that uses a switch instead of a map. I
    think it is a better approach as long as the mapping is static
    Thanks! But I still prefer keeping associations like this in a data
    structure rather than in code. Also, as C is the most similar-looking
    language I already knew, I hadn't realized you could do a meaningful switch
    on string values.

    __John

    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
  • Chris Hines at Jul 10, 2014 at 1:33 pm

    On Thursday, July 10, 2014 8:56:09 AM UTC-4, jcg.s...@gmail.com wrote:
    On Thursday, July 10, 2014 1:37:56 PM UTC+1, Chris Hines wrote:

    Here is an alternate implementation that uses a switch instead of a map.
    I think it is a better approach as long as the mapping is static
    Thanks! But I still prefer keeping associations like this in a data
    structure rather than in code. Also, as C is the most similar-looking
    language I already knew, I hadn't realized you could do a meaningful switch
    on string values.
    That may be the correct answer for your use case.

    I will simply offer that in the map based solution the associations are
    also stored in code--the code that initializes the map.

    Either way, I'm glad we could help.

    Chris

    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
  • Jcg Sturdy at Jul 10, 2014 at 3:43 pm

    On Thursday, July 10, 2014 2:33:10 PM UTC+1, Chris Hines wrote:

    Either way, I'm glad we could help.
    Thanks to all who replied!

    __John

    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.

Related Discussions

Discussion Navigation
viewthread | post
Discussion Overview
groupgolang-nuts @
categoriesgo
postedJul 10, '14 at 11:30a
activeJul 10, '14 at 3:43p
posts11
users4
websitegolang.org

People

Translate

site design / logo © 2022 Grokbase