[go-nuts] Re: On Accepting Interfaces and Structs
Assume the state is the config struct and each implementation is reading it from s different file type (yaml, toml, hlc, json, etc). On Friday, April 27, 2018 at 4:45:33 AM UTC+4:30, Jake Montgomery wrote: > > The example gives me a better understanding of what you are doing, though > still not much understanding as to *why *you are doing it this way. > Usually, if I feel that code has a "smell" in Go, there is a way to rethink > the basic design resulting more "natural" code. But without a full > understanding of the real situation, it is impossible to say if that > applies here. But lets assume for now that you must have multiple packages > that all contain functions that return a common struct. > > >> But I do not like: >> >> >>1. Having a package just to hold a single type, >> >> Personally, I don't see anything inherently wrong with this. If you *must > *multiple packages that all need the type, then it should be in a package > separate from those. In many cases there would be functions that could also > go in package `state`, but if not, then that's ok too. > > 2. The consumer package is accepting a concrete type and depends on it - >> seems this one can not be avoided since there is nothing like structural >> typing for structs in Go. >> > > Your example does feel a bit awkward, but, again, I don't have enough > information on what is really being achieved to suggest a completely > different model. > > But I will take a shot in the dark. Think interfaces? Perhaps the > state.State type returned by Clone() could be an interface? This does not > solve the problem of having to define the interface in a separate package, > and I would only use an interface if there was a compelling reason to do > so. > > Taking a further leap,why "Clone()" at all? What do you do with state.State > in package consumer? Does it have to be a struct for some reason? If you > could define a set of functionality that a consumer needs from state.State, > you could then have Concrete1, Concrete2, and Concrete3 all implement > that functionality. Then consumer can just use them directly as > interfaces ... or perhaps that is using them indirectly. Anyway, I hope > that is somewhat comprehensible. > > Good Luck > - Jake > > On Tuesday, April 24, 2018 at 1:49:45 AM UTC-4, Kaveh Shahbazian wrote: >> >> @Jake @Bryan Thanks! >> >> Current solution I use: >> >> A package that holds the shared data type State: >> >> package state >> >> type State struct { >> Latitude float64 >> Longitude float64 >> Mark string >> Name string >> // ... >> } >> >> Three packages with different implementations and algorithms: >> >> package concrete1 >> >> import ( >> "gitlab.com/dc0d/gist/2018/Q1/draft/cmd/draft/state" >> ) >> >> type Concrete1 struct{} >> >> func (c *Concrete1) Clone() (*state.State, error) { panic("N/A") } >> >> And: >> >> package concrete2 >> >> import ( >> "gitlab.com/dc0d/gist/2018/Q1/draft/cmd/draft/state" >> ) >> >> type Concrete2 struct{} >> >> func (c *Concrete2) Clone() (*state.State, error) { panic("N/A") } >> >> And: >> >> package concrete3 >> >> import ( >> "gitlab.com/dc0d/gist/2018/Q1/draft/cmd/draft/state" >> ) >> >> type Concrete3 struct{} >> >> func (c *Concrete3) Clone() (*state.State, error) { panic("N/A") } >> >> And the consumer package, which will be given a concrete implementation >> based on some logic (this is where "Accepting interfaces" is happening): >> >> package consumer >> >> import ( >> "gitlab.com/dc0d/gist/2018/Q1/draft/cmd/draft/state" >> ) >> >> func Use(cln cloner) {} >> >> type cloner interface { >> Clone() (*state.State, error) >> } >> >> The part in question is the *state.State data type. This is the best I >> could come up with. >> >> But I do not like: >> >> >>1. Having a package just to hold a single type, >>2. The consumer package is accepting a concrete type and depends on >>it - seems this one can not be avoided since there is nothing like >>structural typing for structs in Go. >> >> >> There might be a better way to do this. >> > -- 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+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.
[go-nuts] Re: On Accepting Interfaces and Structs
The example gives me a better understanding of what you are doing, though still not much understanding as to *why *you are doing it this way. Usually, if I feel that code has a "smell" in Go, there is a way to rethink the basic design resulting more "natural" code. But without a full understanding of the real situation, it is impossible to say if that applies here. But lets assume for now that you must have multiple packages that all contain functions that return a common struct. > But I do not like: > > >1. Having a package just to hold a single type, > > Personally, I don't see anything inherently wrong with this. If you *must *multiple packages that all need the type, then it should be in a package separate from those. In many cases there would be functions that could also go in package `state`, but if not, then that's ok too. 2. The consumer package is accepting a concrete type and depends on it - > seems this one can not be avoided since there is nothing like structural > typing for structs in Go. > Your example does feel a bit awkward, but, again, I don't have enough information on what is really being achieved to suggest a completely different model. But I will take a shot in the dark. Think interfaces? Perhaps the state.State type returned by Clone() could be an interface? This does not solve the problem of having to define the interface in a separate package, and I would only use an interface if there was a compelling reason to do so. Taking a further leap,why "Clone()" at all? What do you do with state.State in package consumer? Does it have to be a struct for some reason? If you could define a set of functionality that a consumer needs from state.State, you could then have Concrete1, Concrete2, and Concrete3 all implement that functionality. Then consumer can just use them directly as interfaces ... or perhaps that is using them indirectly. Anyway, I hope that is somewhat comprehensible. Good Luck - Jake On Tuesday, April 24, 2018 at 1:49:45 AM UTC-4, Kaveh Shahbazian wrote: > > @Jake @Bryan Thanks! > > Current solution I use: > > A package that holds the shared data type State: > > package state > > type State struct { > Latitude float64 > Longitude float64 > Mark string > Name string > // ... > } > > Three packages with different implementations and algorithms: > > package concrete1 > > import ( > "gitlab.com/dc0d/gist/2018/Q1/draft/cmd/draft/state" > ) > > type Concrete1 struct{} > > func (c *Concrete1) Clone() (*state.State, error) { panic("N/A") } > > And: > > package concrete2 > > import ( > "gitlab.com/dc0d/gist/2018/Q1/draft/cmd/draft/state" > ) > > type Concrete2 struct{} > > func (c *Concrete2) Clone() (*state.State, error) { panic("N/A") } > > And: > > package concrete3 > > import ( > "gitlab.com/dc0d/gist/2018/Q1/draft/cmd/draft/state" > ) > > type Concrete3 struct{} > > func (c *Concrete3) Clone() (*state.State, error) { panic("N/A") } > > And the consumer package, which will be given a concrete implementation > based on some logic (this is where "Accepting interfaces" is happening): > > package consumer > > import ( > "gitlab.com/dc0d/gist/2018/Q1/draft/cmd/draft/state" > ) > > func Use(cln cloner) {} > > type cloner interface { > Clone() (*state.State, error) > } > > The part in question is the *state.State data type. This is the best I > could come up with. > > But I do not like: > > >1. Having a package just to hold a single type, >2. The consumer package is accepting a concrete type and depends on it >- seems this one can not be avoided since there is nothing like structural >typing for structs in Go. > > > There might be a better way to do this. > -- 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+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.
[go-nuts] Re: On Accepting Interfaces and Structs
In the process of answering your questions I realised there was a number of changes I needed to make to my code, here is the state of it at the commit I just made with this in mind: (this is a permalink and shows how it is at this exact stage) https://github.com/calibrae-project/bast/tree/418af6fc24480cbbc2d7b72bab794f0375439f9c On Tuesday, 24 April 2018 10:19:56 UTC+3, Louki Sumirniy wrote: > > I looked at the OP again and I have created a struct embedding with > interface type for a similar purpose as you have in mind. > > I'm not sure how to condense it exactly, but I'll just explain the salient > points: > > >1. The data has to be referred to via an interface{} which you load >with a struct, and inside the struct is your storage structure, which can >be just a slice array, and in my case it was necessary to embed because >slices don't talk with interface{} in go >2. The functions that are specific to the data type have to be >overridable, so that those that are general can call these functions >without knowing or caring about what the actual data type is. For this I >added the function collection to the primary struct defining the >superclass, if I can call it that, so that you can then use abstract calls >that pass through the interface to the implementation (which can be in a >separate source file if the names are capitalised to be exported) >3. Type specifications for all of the type-specific functions need to >be made, and these form the list of functions inside the superclass type >struct, and then you create an initialiser that loads in the specific >implementation functions > > One little tip I can give with the initialiser is that it can be easier to > use closures to specify the type specific function set. Someone pointed out > that my code was missing the search/insert/delete functions and I actually > didn't realise I'd removed them as I had actually written them > previously... but part of the reason I probably did that was because I > didn't yet know (until pretty much yesterday or the day before) how to bind > and pass interface variables around... so I will need to put those > functions back in now that I know how to abstract the data accessors and > pass through values from the caller without needing to know their types. > > Ideally you narrow the amount of parts that deal with the abstractions as > much as possible, without sacrificing the readability of your code, though > that's a matter of personal preference (I like code that reads like bad > english - not english, but still understandable). In my case, the > search/insert/delete functions could be part of the function set bound to > the type, but they can stay in the higher level of the code if you don't > address their types directly but use the accessor functions set to do this > for you, then inside these functions all the types are known, but the > operations can be tailored to the concrete types. > > So in other words, there is a number of ways to do various different parts > of it and you'll need to read up on them to make your own decision how you > want to implement it. I won't say that my code is exemplary but it will at > least give you some clues as to at least the options I have decided to use > for this. > > On Tuesday, 24 April 2018 09:58:46 UTC+3, Kaveh Shahbazian wrote: >> >> Thanks @Louki, >> >> The names are absolutely made up and are just for the purpose of >> demonstration. >> >> The problem is the package state, one whole package to just hold a type. >> >> On Tuesday, April 24, 2018 at 10:36:29 AM UTC+4:30, Louki Sumirniy wrote: >>> >>> The name could use some work, stutter is a no-no in Go. What kind of >>> state does it hold? User profiles? MMO game world database? Is your scope >>> too broad? I see that it looks like a geography database, so it would make >>> more sense to call it 'geo' or something like this. Also, for such a >>> database system there is waypoints, paths and regions as subtypes that I >>> can think of off the top of my head. Or maybe 'location' is a better name >>> for it. Will there be a history ledger also? >>> >>> I hope that helps you... it's just a namespace question really. The >>> important thing about how to define it has to do with what will be done >>> with it not what it is, as a matter of ontology. Object oriented design >>> methodology tends to look at things like everything can be abstracted and >>> in the real world, categories are containers, like 'car' is the general, >>> 'engine', 'transmission', 'wheels', and inside engine is 'carb/injector' >>> 'pistons' 'cams' 'ignition' inside ignition is ignition timing, throttle >>> etc etc. If you follow a model of containers you will get clean boundaries >>> between things, and the path from user to data will be much more clear. >>> >>> On Tuesday, 24 April 2018 08:49:45 UTC+3, Kaveh Shahbazian wrote:
[go-nuts] Re: On Accepting Interfaces and Structs
I looked at the OP again and I have created a struct embedding with interface type for a similar purpose as you have in mind. I'm not sure how to condense it exactly, but I'll just explain the salient points: 1. The data has to be referred to via an interface{} which you load with a struct, and inside the struct is your storage structure, which can be just a slice array, and in my case it was necessary to embed because slices don't talk with interface{} in go 2. The functions that are specific to the data type have to be overridable, so that those that are general can call these functions without knowing or caring about what the actual data type is. For this I added the function collection to the primary struct defining the superclass, if I can call it that, so that you can then use abstract calls that pass through the interface to the implementation (which can be in a separate source file if the names are capitalised to be exported) 3. Type specifications for all of the type-specific functions need to be made, and these form the list of functions inside the superclass type struct, and then you create an initialiser that loads in the specific implementation functions One little tip I can give with the initialiser is that it can be easier to use closures to specify the type specific function set. Someone pointed out that my code was missing the search/insert/delete functions and I actually didn't realise I'd removed them as I had actually written them previously... but part of the reason I probably did that was because I didn't yet know (until pretty much yesterday or the day before) how to bind and pass interface variables around... so I will need to put those functions back in now that I know how to abstract the data accessors and pass through values from the caller without needing to know their types. Ideally you narrow the amount of parts that deal with the abstractions as much as possible, without sacrificing the readability of your code, though that's a matter of personal preference (I like code that reads like bad english - not english, but still understandable). In my case, the search/insert/delete functions could be part of the function set bound to the type, but they can stay in the higher level of the code if you don't address their types directly but use the accessor functions set to do this for you, then inside these functions all the types are known, but the operations can be tailored to the concrete types. So in other words, there is a number of ways to do various different parts of it and you'll need to read up on them to make your own decision how you want to implement it. I won't say that my code is exemplary but it will at least give you some clues as to at least the options I have decided to use for this. On Tuesday, 24 April 2018 09:58:46 UTC+3, Kaveh Shahbazian wrote: > > Thanks @Louki, > > The names are absolutely made up and are just for the purpose of > demonstration. > > The problem is the package state, one whole package to just hold a type. > > On Tuesday, April 24, 2018 at 10:36:29 AM UTC+4:30, Louki Sumirniy wrote: >> >> The name could use some work, stutter is a no-no in Go. What kind of >> state does it hold? User profiles? MMO game world database? Is your scope >> too broad? I see that it looks like a geography database, so it would make >> more sense to call it 'geo' or something like this. Also, for such a >> database system there is waypoints, paths and regions as subtypes that I >> can think of off the top of my head. Or maybe 'location' is a better name >> for it. Will there be a history ledger also? >> >> I hope that helps you... it's just a namespace question really. The >> important thing about how to define it has to do with what will be done >> with it not what it is, as a matter of ontology. Object oriented design >> methodology tends to look at things like everything can be abstracted and >> in the real world, categories are containers, like 'car' is the general, >> 'engine', 'transmission', 'wheels', and inside engine is 'carb/injector' >> 'pistons' 'cams' 'ignition' inside ignition is ignition timing, throttle >> etc etc. If you follow a model of containers you will get clean boundaries >> between things, and the path from user to data will be much more clear. >> >> On Tuesday, 24 April 2018 08:49:45 UTC+3, Kaveh Shahbazian wrote: >>> >>> @Jake @Bryan Thanks! >>> >>> Current solution I use: >>> >>> A package that holds the shared data type State: >>> >>> package state >>> >>> type State struct { >>> Latitude float64 >>> Longitude float64 >>> Mark string >>> Name string >>> // ... >>> } >>> >>> Three packages with different implementations and algorithms: >>> >>> package concrete1 >>> >>> import ( >>> "gitlab.com/dc0d/gist/2018/Q1/draft/cmd/draft/state" >>> ) >>> >>> type Concrete1 struct{} >>> >>> func (c *Concrete1) Clone()
[go-nuts] Re: On Accepting Interfaces and Structs
Thanks @Louki, The names are absolutely made up and are just for the purpose of demonstration. The problem is the package state, one whole package to just hold a type. On Tuesday, April 24, 2018 at 10:36:29 AM UTC+4:30, Louki Sumirniy wrote: > > The name could use some work, stutter is a no-no in Go. What kind of state > does it hold? User profiles? MMO game world database? Is your scope too > broad? I see that it looks like a geography database, so it would make more > sense to call it 'geo' or something like this. Also, for such a database > system there is waypoints, paths and regions as subtypes that I can think > of off the top of my head. Or maybe 'location' is a better name for it. > Will there be a history ledger also? > > I hope that helps you... it's just a namespace question really. The > important thing about how to define it has to do with what will be done > with it not what it is, as a matter of ontology. Object oriented design > methodology tends to look at things like everything can be abstracted and > in the real world, categories are containers, like 'car' is the general, > 'engine', 'transmission', 'wheels', and inside engine is 'carb/injector' > 'pistons' 'cams' 'ignition' inside ignition is ignition timing, throttle > etc etc. If you follow a model of containers you will get clean boundaries > between things, and the path from user to data will be much more clear. > > On Tuesday, 24 April 2018 08:49:45 UTC+3, Kaveh Shahbazian wrote: >> >> @Jake @Bryan Thanks! >> >> Current solution I use: >> >> A package that holds the shared data type State: >> >> package state >> >> type State struct { >> Latitude float64 >> Longitude float64 >> Mark string >> Name string >> // ... >> } >> >> Three packages with different implementations and algorithms: >> >> package concrete1 >> >> import ( >> "gitlab.com/dc0d/gist/2018/Q1/draft/cmd/draft/state" >> ) >> >> type Concrete1 struct{} >> >> func (c *Concrete1) Clone() (*state.State, error) { panic("N/A") } >> >> And: >> >> package concrete2 >> >> import ( >> "gitlab.com/dc0d/gist/2018/Q1/draft/cmd/draft/state" >> ) >> >> type Concrete2 struct{} >> >> func (c *Concrete2) Clone() (*state.State, error) { panic("N/A") } >> >> And: >> >> package concrete3 >> >> import ( >> "gitlab.com/dc0d/gist/2018/Q1/draft/cmd/draft/state" >> ) >> >> type Concrete3 struct{} >> >> func (c *Concrete3) Clone() (*state.State, error) { panic("N/A") } >> >> And the consumer package, which will be given a concrete implementation >> based on some logic (this is where "Accepting interfaces" is happening): >> >> package consumer >> >> import ( >> "gitlab.com/dc0d/gist/2018/Q1/draft/cmd/draft/state" >> ) >> >> func Use(cln cloner) {} >> >> type cloner interface { >> Clone() (*state.State, error) >> } >> >> The part in question is the *state.State data type. This is the best I >> could come up with. >> >> But I do not like: >> >> >>1. Having a package just to hold a single type, >>2. The consumer package is accepting a concrete type and depends on >>it - seems this one can not be avoided since there is nothing like >>structural typing for structs in Go. >> >> >> There might be a better way to do this. >> > -- 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+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.
[go-nuts] Re: On Accepting Interfaces and Structs
The name could use some work, stutter is a no-no in Go. What kind of state does it hold? User profiles? MMO game world database? Is your scope too broad? I see that it looks like a geography database, so it would make more sense to call it 'geo' or something like this. Also, for such a database system there is waypoints, paths and regions as subtypes that I can think of off the top of my head. Or maybe 'location' is a better name for it. Will there be a history ledger also? I hope that helps you... it's just a namespace question really. The important thing about how to define it has to do with what will be done with it not what it is, as a matter of ontology. Object oriented design methodology tends to look at things like everything can be abstracted and in the real world, categories are containers, like 'car' is the general, 'engine', 'transmission', 'wheels', and inside engine is 'carb/injector' 'pistons' 'cams' 'ignition' inside ignition is ignition timing, throttle etc etc. If you follow a model of containers you will get clean boundaries between things, and the path from user to data will be much more clear. On Tuesday, 24 April 2018 08:49:45 UTC+3, Kaveh Shahbazian wrote: > > @Jake @Bryan Thanks! > > Current solution I use: > > A package that holds the shared data type State: > > package state > > type State struct { > Latitude float64 > Longitude float64 > Mark string > Name string > // ... > } > > Three packages with different implementations and algorithms: > > package concrete1 > > import ( > "gitlab.com/dc0d/gist/2018/Q1/draft/cmd/draft/state" > ) > > type Concrete1 struct{} > > func (c *Concrete1) Clone() (*state.State, error) { panic("N/A") } > > And: > > package concrete2 > > import ( > "gitlab.com/dc0d/gist/2018/Q1/draft/cmd/draft/state" > ) > > type Concrete2 struct{} > > func (c *Concrete2) Clone() (*state.State, error) { panic("N/A") } > > And: > > package concrete3 > > import ( > "gitlab.com/dc0d/gist/2018/Q1/draft/cmd/draft/state" > ) > > type Concrete3 struct{} > > func (c *Concrete3) Clone() (*state.State, error) { panic("N/A") } > > And the consumer package, which will be given a concrete implementation > based on some logic (this is where "Accepting interfaces" is happening): > > package consumer > > import ( > "gitlab.com/dc0d/gist/2018/Q1/draft/cmd/draft/state" > ) > > func Use(cln cloner) {} > > type cloner interface { > Clone() (*state.State, error) > } > > The part in question is the *state.State data type. This is the best I > could come up with. > > But I do not like: > > >1. Having a package just to hold a single type, >2. The consumer package is accepting a concrete type and depends on it >- seems this one can not be avoided since there is nothing like structural >typing for structs in Go. > > > There might be a better way to do this. > -- 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+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.
[go-nuts] Re: On Accepting Interfaces and Structs
@Jake @Bryan Thanks! Current solution I use: A package that holds the shared data type State: package state type State struct { Latitude float64 Longitude float64 Mark string Name string // ... } Three packages with different implementations and algorithms: package concrete1 import ( "gitlab.com/dc0d/gist/2018/Q1/draft/cmd/draft/state" ) type Concrete1 struct{} func (c *Concrete1) Clone() (*state.State, error) { panic("N/A") } And: package concrete2 import ( "gitlab.com/dc0d/gist/2018/Q1/draft/cmd/draft/state" ) type Concrete2 struct{} func (c *Concrete2) Clone() (*state.State, error) { panic("N/A") } And: package concrete3 import ( "gitlab.com/dc0d/gist/2018/Q1/draft/cmd/draft/state" ) type Concrete3 struct{} func (c *Concrete3) Clone() (*state.State, error) { panic("N/A") } And the consumer package, which will be given a concrete implementation based on some logic (this is where "Accepting interfaces" is happening): package consumer import ( "gitlab.com/dc0d/gist/2018/Q1/draft/cmd/draft/state" ) func Use(cln cloner) {} type cloner interface { Clone() (*state.State, error) } The part in question is the *state.State data type. This is the best I could come up with. But I do not like: 1. Having a package just to hold a single type, 2. The consumer package is accepting a concrete type and depends on it - seems this one can not be avoided since there is nothing like structural typing for structs in Go. There might be a better way to do this. -- 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+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.
[go-nuts] Re: On Accepting Interfaces and Structs
I agree with Jake: a more complete example would be helpful. In my experience, this sort of issue is often a symptom of awkward package boundaries. If you can find a more natural package boundary, you may be able to sidestep the problem. (There are certainly some cases where the lack of covariance makes interfaces difficult to construct, but those cases tend to be rare.) On Monday, April 23, 2018 at 12:08:38 PM UTC-4, Jake Montgomery wrote: > > My gut feeling is that there is an elegant way to achieve what you want. > Unfortunately, I am having trouble following the code you are describing, > and more importantly, what you are actually trying to accomplish. Perhaps > it is my failing. > > If you would post a more complete example, showing the relevant code in > all the related packages, I suspect you would get constructive suggestions. > > - Jake > > > On Saturday, April 21, 2018 at 7:51:55 AM UTC-4, Kaveh Shahbazian wrote: >> >> Regarding "Accept interfaces, return concrete types", how can it be >> applied for structs that represent a payload/value? >> >> For example in package first, logger is defined as: >> >> type logger interface { >> Debugf(template string, args ...interface{}) >> Errorf(template string, args ...interface{}) >> Infof(template string, args ...interface{}) >> } >> >> And package first only accepts a logger that implements the logger >> interface. >> >> Now lets assume there is a need for passing a struct too, like some >> config or state. >> >> This causes importing the original package that, that config or state >> struct resides in; while package first is happily accepting other things >> from that package using interfaces. >> >> For example in package second there is some tool that is represented >> using this interface in package first: >> >> type cloner interface { >> Clone() (*second.State, error) >> } >> >> >> As it can be seen, now package first has to explicitly import package >> second, because of the type *second.State. >> >> Currently I break things by renaming the second package to something >> meaningless when importing like: >> >> type cloner interface { >> Clone() (*p2nd.State, error) >> } >> >> But this is not really a work around and package second leaks into the >> scope of package first anyway. >> >> Is there a way to actually achieve this? >> > -- 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+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.
[go-nuts] Re: On Accepting Interfaces and Structs
My gut feeling is that there is an elegant way to achieve what you want. Unfortunately, I am having trouble following the code you are describing, and more importantly, what you are actually trying to accomplish. Perhaps it is my failing. If you would post a more complete example, showing the relevant code in all the related packages, I suspect you would get constructive suggestions. - Jake On Saturday, April 21, 2018 at 7:51:55 AM UTC-4, Kaveh Shahbazian wrote: > > Regarding "Accept interfaces, return concrete types", how can it be > applied for structs that represent a payload/value? > > For example in package first, logger is defined as: > > type logger interface { > Debugf(template string, args ...interface{}) > Errorf(template string, args ...interface{}) > Infof(template string, args ...interface{}) > } > > And package first only accepts a logger that implements the logger > interface. > > Now lets assume there is a need for passing a struct too, like some config > or state. > > This causes importing the original package that, that config or state > struct resides in; while package first is happily accepting other things > from that package using interfaces. > > For example in package second there is some tool that is represented using > this interface in package first: > > type cloner interface { > Clone() (*second.State, error) > } > > > As it can be seen, now package first has to explicitly import package > second, because of the type *second.State. > > Currently I break things by renaming the second package to something > meaningless when importing like: > > type cloner interface { > Clone() (*p2nd.State, error) > } > > But this is not really a work around and package second leaks into the > scope of package first anyway. > > Is there a way to actually achieve this? > -- 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+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.
[go-nuts] Re: On Accepting Interfaces and Structs
The State type is just a POGO with no methods. The part that changes is the implementation of Clone() (State, error) method. On Sunday, April 22, 2018 at 5:18:00 AM UTC+4:30, Louki Sumirniy wrote: > > I only just finally wrapped my head around this stuff and forgive me if I > have missed the point of the question but this is what my code has: > > type AbstractType alias/struct {} > > type abstractthing interface { > DoSomething(interface{}) > } > > func (a *AbstractType) DoSomething(b AbstractType) { > > } > > and then in my implementer: > > import ( > "previousclass/path" > ) > > type ConcreteType alias/struct {} > > func (c *ConcreteType) DoSomething(t ConcreteType) { > > } > > You have to create a dummy function in the abstract type's source file in > order to use it in the superclass, as it effectively is, in order to use > its generalised functionality, but your app imports the second one, which > sucks up everything from the first and the function bound to the concrete > type overrides the abstract functions in the superclass, allowing you to > generalise part of the superclass and enable you to write a set of > functions with part of the implementation (for example, a tree store) while > letting you change the data type to something else. It's composition, as > opposed to inheritance. > > On Saturday, 21 April 2018 14:51:55 UTC+3, Kaveh Shahbazian wrote: >> >> Regarding "Accept interfaces, return concrete types", how can it be >> applied for structs that represent a payload/value? >> >> For example in package first, logger is defined as: >> >> type logger interface { >> Debugf(template string, args ...interface{}) >> Errorf(template string, args ...interface{}) >> Infof(template string, args ...interface{}) >> } >> >> And package first only accepts a logger that implements the logger >> interface. >> >> Now lets assume there is a need for passing a struct too, like some >> config or state. >> >> This causes importing the original package that, that config or state >> struct resides in; while package first is happily accepting other things >> from that package using interfaces. >> >> For example in package second there is some tool that is represented >> using this interface in package first: >> >> type cloner interface { >> Clone() (*second.State, error) >> } >> >> >> As it can be seen, now package first has to explicitly import package >> second, because of the type *second.State. >> >> Currently I break things by renaming the second package to something >> meaningless when importing like: >> >> type cloner interface { >> Clone() (*p2nd.State, error) >> } >> >> But this is not really a work around and package second leaks into the >> scope of package first anyway. >> >> Is there a way to actually achieve this? >> > -- 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+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.
[go-nuts] Re: On Accepting Interfaces and Structs
I only just finally wrapped my head around this stuff and forgive me if I have missed the point of the question but this is what my code has: type AbstractType alias/struct {} type abstractthing interface { DoSomething(interface{}) } func (a *AbstractType) DoSomething(b AbstractType) { } and then in my implementer: import ( "previousclass/path" ) type ConcreteType alias/struct {} func (c *ConcreteType) DoSomething(t ConcreteType) { } You have to create a dummy function in the abstract type's source file in order to use it in the superclass, as it effectively is, in order to use its generalised functionality, but your app imports the second one, which sucks up everything from the first and the function bound to the concrete type overrides the abstract functions in the superclass, allowing you to generalise part of the superclass and enable you to write a set of functions with part of the implementation (for example, a tree store) while letting you change the data type to something else. It's composition, as opposed to inheritance. On Saturday, 21 April 2018 14:51:55 UTC+3, Kaveh Shahbazian wrote: > > Regarding "Accept interfaces, return concrete types", how can it be > applied for structs that represent a payload/value? > > For example in package first, logger is defined as: > > type logger interface { > Debugf(template string, args ...interface{}) > Errorf(template string, args ...interface{}) > Infof(template string, args ...interface{}) > } > > And package first only accepts a logger that implements the logger > interface. > > Now lets assume there is a need for passing a struct too, like some config > or state. > > This causes importing the original package that, that config or state > struct resides in; while package first is happily accepting other things > from that package using interfaces. > > For example in package second there is some tool that is represented using > this interface in package first: > > type cloner interface { > Clone() (*second.State, error) > } > > > As it can be seen, now package first has to explicitly import package > second, because of the type *second.State. > > Currently I break things by renaming the second package to something > meaningless when importing like: > > type cloner interface { > Clone() (*p2nd.State, error) > } > > But this is not really a work around and package second leaks into the > scope of package first anyway. > > Is there a way to actually achieve this? > -- 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+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.