[go-nuts] Re: On Accepting Interfaces and Structs

2018-04-27 Thread Kaveh Shahbazian
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

2018-04-26 Thread jake6502
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

2018-04-24 Thread Louki Sumirniy
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

2018-04-24 Thread Louki Sumirniy
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

2018-04-24 Thread Kaveh Shahbazian
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

2018-04-24 Thread Louki Sumirniy
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

2018-04-23 Thread Kaveh Shahbazian
@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

2018-04-23 Thread 'Bryan Mills' via golang-nuts
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

2018-04-23 Thread jake6502
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

2018-04-22 Thread Kaveh Shahbazian
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

2018-04-21 Thread Louki Sumirniy
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.