FAQ
Here's something that doesn't work.. basically I'm trying to save some
typing - plus other "logical" reasons

I've got an interface (used for converting 3d onto 2d projections)

type Canvas3type interface {

     GetCanvasXY(vectors.P3d) CanvasXY

     GetCanvas() *Canvas

}

and a second interface I use to draw using similar objects (other non
Canvas3type objects also implement this

type Canvas3type_drawable interface {

     Line(vectors.P3d, vectors.P3d)

}


It turns out that all canvas3type values will also be able to satisfy
canvas3type_drawable without extra work because they have by definition the
methods I need.. But I need to write out the specific Plot and Line methods
for each instance.

What I'd like to do is this (I have a "ton" of Canvas3type objects )

func (c Canvas3type) Line(p1, p2 vectors.P3d) {

     c.GetCanvas().Draw_line(c.GetCanvasXY(p1),c.GetCanvasXY(p2))

}


(Canvas has a Draw-line method not shown here)

I don't see a contradiction in terms of "interfaces describe behaviour"
philosophy - to me allowing/implementing this seems like it could be a
really good idea - seems to solve multiple inheritance type problems from
the rear (if that makes sense?) - I haven't thought about it in huge detail

My question - Just wondering - bad idea to allow/implement this, or good
idea but difficult to do? Or is there another way to achieve what I want
here. Feedback welcomed

--
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

  • Daniël de Kok at Jun 27, 2015 at 9:42 am

    On Sat, Jun 27, 2015, at 01:06, xiiophen@gmail.com wrote:
    I don't see a contradiction in terms of "interfaces describe
    behaviour" philosophy - to me allowing/implementing this seems like it
    could be a really good idea - seems to solve multiple inheritance type
    problems from the rear (if that makes sense?) - I haven't thought
    about it in huge detail

    My question - Just wondering - bad idea to allow/implement this, or
    good idea but difficult to do? Or is there another way to achieve what
    I want here. Feedback welcomed
    What you want looks like Java 8 traits. It's currently not
    possible, because the method set of an interface can only be
    defined *in* the interface

    However, since Go has anonymous fields, you can easily create a wrapper
    struct and implement the interface on the wrapper:

    http://play.golang.org/p/GoVwItLRWx

    Moreover, if it is possible to factor out struct members that are needed
    to provide this interface to a separate struct, you could simply define
    the interface on that struct and embed it in all your current structs.
    Then all embedding structs will fulfil the interface. E.g.:

    http://play.golang.org/p/bDR52dw4PE

    Take care,
    Daniël de Kok

    --
    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.
  • Daniël de Kok at Jun 27, 2015 at 10:31 am

    On Sat, Jun 27, 2015, at 11:42, Daniël de Kok wrote:
    What you want looks like Java 8 traits. It's currently not possible,
    because the method set of an interface can only be defined *in* the
    interface
    Oh, by the way, your interface name 'Canvas3type_drawable' suggests that
    you are going to define this for Canvas3types primarily. Is so, why not
    define
    a standalone function

    func Line(Canvas3type, vectors.P3d, vectors.P3d)

    ?

    Take care,
    Daniël

    --
    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.
  • Xiiophen at Jun 27, 2015 at 10:48 am

    On Saturday, 27 June 2015 11:31:59 UTC+1, Daniël de Kok wrote:
    On Sat, Jun 27, 2015, at 11:42, Daniël de Kok wrote:
    What you want looks like Java 8 traits. It's currently not possible,
    because the method set of an interface can only be defined *in* the
    interface
    Oh, by the way, your interface name 'Canvas3type_drawable' suggests that
    you are going to define this for Canvas3types primarily. Is so, why not
    define
    a standalone function

    func Line(Canvas3type, vectors.P3d, vectors.P3d)

    ?

    Take care,
    Daniël
    I actually have some other similar s types that embed multiple Canvas3types
    - these have a Line methods that draw to the individually canvases

    ie


    type Canvas3xyz struct {

         X, Y, Z Canvas3type // 3 projection directions

         Big Canvas

         height, width int

    }


    has a Line method that draws to all three (X,Y,Z) Canvas3type simultaneously- so it implements Canvas3type_drawable, but doesn't/cannot implement Canvas3type


    I have utility functions like DrawRect that take either type as a Canvas3type_drawable


    I think it makes sense..

    --
    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.
  • Xiiophen at Jun 27, 2015 at 10:38 am
    Thanks. I'll look at the structs way and see if it makes my life easier.

    As an aside, if anyone is reading, whilst thinking about this it occurred
    to me that *if* the feature was implemented then there would need to be
    some way to ensure that the method was not overridden - oone solution would
    be like this

    type extensible interface {
       A()
       ! B()
    }


    meaning that for "extensible" to be implemented an object must have an A()
    method, AND NOT a B() method. ( B() can then be extended on the interface
    if desired.)

    I can't really see a justifiable use for this - though it looked
    interesting.

    --
    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.
  • Marvin Renich at Jun 27, 2015 at 11:29 pm
    [ Please don't CC me; I am subscribed. ]

    * xiiophen@gmail.com [150627 04:15]:
    I've got an interface (used for converting 3d onto 2d projections)

    type Canvas3type interface {

    GetCanvasXY(vectors.P3d) CanvasXY

    GetCanvas() *Canvas

    }

    What I'd like to do is this (I have a "ton" of Canvas3type objects )

    func (c Canvas3type) Line(p1, p2 vectors.P3d) {

    c.GetCanvas().Draw_line(c.GetCanvasXY(p1),c.GetCanvasXY(p2))

    }
    I would do this without attempting to create a method; use a simple
    function:

    func Line(c Canvas3type, p1, p2 vectors.P3d) {
         c.GetCanvas().Draw_line(c.GetCanvasXY(p1),c.GetCanvasXY(p2))
    }

    ...Marvin

    --
    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.
  • Xiiophen at Jun 28, 2015 at 11:20 am

    On Sunday, 28 June 2015 00:29:15 UTC+1, Marvin Renich wrote:
    [ Please don't CC me; I am subscribed. ]

    * xiio...@gmail.com <javascript:> <xiio...@gmail.com <javascript:>>
    [150627 04:15]:
    I've got an interface (used for converting 3d onto 2d projections)

    type Canvas3type interface {

    GetCanvasXY(vectors.P3d) CanvasXY

    GetCanvas() *Canvas

    }

    What I'd like to do is this (I have a "ton" of Canvas3type objects )

    func (c Canvas3type) Line(p1, p2 vectors.P3d) {

    c.GetCanvas().Draw_line(c.GetCanvasXY(p1),c.GetCanvasXY(p2))

    }
    I would do this without attempting to create a method; use a simple
    function:

    func Line(c Canvas3type, p1, p2 vectors.P3d) {
    c.GetCanvas().Draw_line(c.GetCanvasXY(p1),c.GetCanvasXY(p2))
    }

    ...Marvin
    That wouldn't implement the Canvas3type_drawable interface which is what I
    need to do - so I can pass different struct types to a draw function ..
    otherwise , yes it's equivalent

    --
    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.
  • Marvin Renich at Jun 29, 2015 at 12:23 pm
    [ Please don't CC me; I am subscribed. ]
    [ Please don't CC me; I am subscribed. ]
    * xiiophen@gmail.com [150627 04:15]:
    type Canvas3type interface {
    GetCanvasXY(vectors.P3d) CanvasXY
    GetCanvas() *Canvas
    }

    type Canvas3type_drawable interface {
    Line(vectors.P3d, vectors.P3d)
    }

    func (c Canvas3type) Line(p1, p2 vectors.P3d) {
    c.GetCanvas().Draw_line(c.GetCanvasXY(p1),c.GetCanvasXY(p2))
    }
    On Sunday, 28 June 2015 00:29:15 UTC+1, Marvin Renich wrote:
    I would do this without attempting to create a method; use a simple
    function:

    func Line(c Canvas3type, p1, p2 vectors.P3d) {
    c.GetCanvas().Draw_line(c.GetCanvasXY(p1),c.GetCanvasXY(p2))
    }
    * xiiophen@gmail.com [150628 07:20]:
    That wouldn't implement the Canvas3type_drawable interface which is what I
    need to do - so I can pass different struct types to a draw function ..
    otherwise , yes it's equivalent
    If I understand, you are saying that some types satisfy
    Canvas3type_drawable but do not satisfy Canvas3type (this is what I did
    not understand the first time). However all types that satisfy
    Canvas3type can trivially implement Canvas3type_drawable with the
    one-liner that you gave above. You are looking for a way to either
    avoid copy/paste or to avoid multiplying the maintenance burden or both.

    I have a couple suggestions. First, I haven't looked at go generate
    yet, but it might be helpful here. Second, this won't help with typing,
    but might help prevent mistakes in bug fixes of many copies: implement
    the Line function as I suggested and then make each method call the Line
    function. If the Line function were many lines long, this would
    definitely be a more useful suggestion, but maybe not so much for this
    one-liner.

    There are several variations of my third suggestion. The basic
    suggestion is to have a wrapper struct:

    type Canvas3TypeToDrawable struct {
         c Canvas3type
    }

    func (d Canvas3TypeToDrawable) Line(p1, p2 vectors.P3d) {
         d.c.GetCanvas().Draw_line(d.c.GetCanvasXY(p1), d.c.GetCanvasXY(p2))
    }

    Now, when you have a Canvas3type and need a Canvas3type_drawable, simply
    wrap it: Canvas3TypeToDrawable{some_canvas3type_variable}.

    If your functions that take a Canvas3type_drawable never type-assert
    that argument back to some other type, this should work perfectly. If
    they are already using a type switch or type assertion, add a little
    more code to check for the wrapper type, and make the member exported so
    that you can extract it. Or better yet, implement the Canvas3type
    methods on your wrapper struct. If there are other interfaces that can
    trivially be implemented by any Canvas3type, just add their methods to
    the wrapper struct.

    ...Marvin

    --
    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.
  • Egon at Jun 28, 2015 at 10:25 am

    On Saturday, 27 June 2015 11:15:22 UTC+3, xiio...@gmail.com wrote:
    Here's something that doesn't work.. basically I'm trying to save some
    typing - plus other "logical" reasons
    Quick notes:

    I've got an interface (used for converting 3d onto 2d projections)

    type Canvas3type interface {

    GetCanvasXY(vectors.P3d) CanvasXY

    GetCanvas() *Canvas

    }
    Try to follow Go naming conventions. e.g.
    use a package canvas, with type Interface:

    package canvas
    type Interface {
         Line(x, y P3)

         SetTransform(m M4)
    }

    Now to implement a projection, create an appropriate projection matrix,
    then multiply all coordinates inside the canvas.

    Basically I cannot see a reason why you would need a separate type for
    converting points.
    (http://www.codinglabs.net/article_world_view_projection_matrix.aspx)

    Of course I do understand that there might be a reason for it. If that's
    the case, can you give a fuller explanation what you are implementing and
    what is the real world application of this.

    + Egon

    >

    --
    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.
  • Xiiophen at Jun 28, 2015 at 11:28 am

    On Sunday, 28 June 2015 11:25:26 UTC+1, Egon wrote:
    On Saturday, 27 June 2015 11:15:22 UTC+3, xiio...@gmail.com wrote:

    Here's something that doesn't work.. basically I'm trying to save some
    typing - plus other "logical" reasons
    Quick notes:

    I've got an interface (used for converting 3d onto 2d projections)

    type Canvas3type interface {

    GetCanvasXY(vectors.P3d) CanvasXY

    GetCanvas() *Canvas

    }
    Try to follow Go naming conventions. e.g.
    use a package canvas, with type Interface:

    package canvas
    type Interface {
    Line(x, y P3)

    SetTransform(m M4)
    }

    Now to implement a projection, create an appropriate projection matrix,
    then multiply all coordinates inside the canvas.

    Basically I cannot see a reason why you would need a separate type for
    converting points. (
    http://www.codinglabs.net/article_world_view_projection_matrix.aspx)

    Of course I do understand that there might be a reason for it. If that's
    the case, can you give a fuller explanation what you are implementing and
    what is the real world application of this.

    + Egon
    I'm already familiar with 3d/2d transforms etc - that code isn't shown here
    because it isn't relavent.to what I was asking.

    In terms of naming conventions - yes it needs improvement - it already is
    in package "canvas" and the interface name is "Canvas3type" giving
    canvas.Canvas3type .. some stuttering there - I haven't got round to making
    this better. Your supplied code doesn't compile.

    I appreciate that I could have supplied a transform matrix (struct) for
    each projection type, avoiding using a GetCanvasXY - the reason for this is
    A. It's the way it got written. B. Code is optimised for specifc
    projections avoiding unnecessary math as would be found in a general
    solution. C. Some projections are using "spherical projections" requiring
    maths like arcan(fn(x)) - afaik the 4x4 matrix representation you suggest
    cannot represent such things.

    --
    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.
  • Egon Elbre at Jun 28, 2015 at 12:22 pm
    On Sunday, June 28, 2015, wrote:
    On Sunday, 28 June 2015 11:25:26 UTC+1, Egon wrote:
    On Saturday, 27 June 2015 11:15:22 UTC+3, xiio...@gmail.com wrote:

    Here's something that doesn't work.. basically I'm trying to save some
    typing - plus other "logical" reasons
    Quick notes:

    I've got an interface (used for converting 3d onto 2d projections)

    type Canvas3type interface {

    GetCanvasXY(vectors.P3d) CanvasXY

    GetCanvas() *Canvas

    }
    Try to follow Go naming conventions. e.g.
    use a package canvas, with type Interface:

    package canvas
    type Interface {
    Line(x, y P3)

    SetTransform(m M4)
    }

    Now to implement a projection, create an appropriate projection matrix,
    then multiply all coordinates inside the canvas.

    Basically I cannot see a reason why you would need a separate type for
    converting points. (
    http://www.codinglabs.net/article_world_view_projection_matrix.aspx)

    Of course I do understand that there might be a reason for it. If that's
    the case, can you give a fuller explanation what you are implementing and
    what is the real world application of this.

    + Egon
    I'm already familiar with 3d/2d transforms etc - that code isn't
    shown here because it isn't relavent.to what I was asking.
    Sure, It's hard to tell from the question alone. I can fathom a case where
    a person would stumble onto such design when he/she wasn't aware of
    transformation and didn't have the complicated transformation cases.

    Sometimes the whole design is relevant - there's one particular dilemma I
    see with questions. How do you know what is relevant to the answer if you
    don't know what the answer is? Of course it's a bit hyperbolic, a good
    intuition/deduction goes a long way. Often when you structure the
    surrounding code differently the immediate problem becomes trivial. It's
    nothing personal, just something I notice quite often, with myself and
    others.

    tl;dr; my gut feeling / intuition that this interface design is wrong, but
    I cannot exactly say how or why, because it would require more information
    about the project than is given.

    Rule of thumb in Go, for me, usually is - when you are thinking about types
    and interfaces and they don't seem to fit together - it's probably because
    you made a design mistake elsewhere.

    Of course, I'm not eliminating that it's a good solution when taking into
    account all constraints.

    Anyways, do you have the code uploaded somewhere? That way it's faster than
    trying to explain the full project. If you don't or can't, no worries, I
    can understand NDAs and such.

    In terms of naming conventions - yes it needs improvement - it already is
    in package "canvas" and the interface name is "Canvas3type" giving
    canvas.Canvas3type .. some stuttering there - I haven't got round to making
    this better. Your supplied code doesn't compile.
      Sorry about the missing interface.

    I appreciate that I could have supplied a transform matrix (struct) for
    each projection type, avoiding using a GetCanvasXY - the reason for this is
    A. It's the way it got written. B. Code is optimised for specifc
    projections avoiding unnecessary math as would be found in a general
    solution.
    Note, you might be losing a lot of performance by passing each point
    through the interface. Passing a slice of points should be faster, when you
    have a lot of them.

    C. Some projections are using "spherical projections" requiring maths like
    arcan(fn(x)) - afaik the 4x4 matrix representation you suggest cannot
    represent such things.

    Then that design doesn't make sense to me. I.e. a line in 3d after a
    spherical transformation would become a curve in 2d, so I'm not sure
    whether you are doing something additional there to compansate for that.

    Alternatively, I just don't understand, from the interfaces alone, how
    things fit together.

    Are you doing some kind of plotting of surfaces, that's the only place I
    can think of it working.

    + Egon
    (sorry for the duplicate email, meant to reply to all)

    --
    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.
  • Xiiophen at Jun 28, 2015 at 1:16 pm
    Very quickly

    "tl;dr; my gut feeling / intuition that this interface design is wrong,
    but I cannot exactly say how or why, because it would require more
    information about the project than is given."

    Actually the interfaces are working out really well - I was thinking about
    an extension that would save a little typing/boilerplate in some closely
    similar types that all satisified a particular interface

    "Then that design doesn't make sense to me. I.e. a line in 3d after a
    spherical transformation would become a curve in 2d, so I'm not sure
    whether you are doing something additional there to compansate for that."
    That's what happens in that case - the Line method calls an individual
    Plot method (I omitted that because it wasn't relavent to the original)
    "Alternatively, I just don't understand, from the interfaces alone, how
    things fit together."
    It's intended for generic use, including ray casting - I also have a use
    case where I combine three ("isometric") projections onto a single object
    that satisfies the Canvas3type_drawable interface - this is why I have two
    levels of interface - some Line methods draw to a single canvas object,
    others draw to multiple render targets (multiple projections) eg
    https://en.wikipedia.org/wiki/Multiview_orthographic_projection and things
    like that

    --
    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.
  • Xiiophen at Jun 28, 2015 at 1:24 pm
    @Egon - here's an example of the code that uses the interface:

    //draw_para draws a parallelepiped defined by origin o, and edge vectors
    a,b,c

    func draw_para(ca canvas.Canvas3type_drawable, o, a, b, c vectors.P3d, col color.NRGBA) {



         ps := [8]vectors.P3d{

             o,

             o.Add_ret(a),

             o.Add_ret(b),

             o.Add_ret(c),

             o.Add_ret(a).Add_ret(b),

             o.Add_ret(a).Add_ret(c),

             o.Add_ret(b).Add_ret(c),

             o.Add_ret(a).Add_ret(b).Add_ret(c),

         }



         for i := 0; i < 8; i++ {

             for j := i + 1; j < 8; j++ {

                 ca.Line(ps[i], ps[j], col)



             }

         }

    }



      It draws a parallelepiped - using the Line method that canvas.Canvas3type_drawable
    must implement.
    In a simple single screen example the Line method just draws one
    parallelepiped from one projection.
    But in the extended case it draws the object from 3 viewpoints etc. The
    target drawn to is a different struct type - hence the need to use an
    interface receiver (The Add_ret methods etc are just some vector math
    helper functions)

    --
    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.
  • Egon Elbre at Jun 28, 2015 at 1:44 pm

    On Sunday, June 28, 2015, wrote:

    @Egon - here's an example of the code that uses the interface:

    //draw_para draws a parallelepiped defined by origin o, and edge vectors
    a,b,c

    func draw_para(ca canvas.Canvas3type_drawable, o, a, b, c vectors.P3d, col color.NRGBA) {



    ps := [8]vectors.P3d{

    o,

    o.Add_ret(a),

    o.Add_ret(b),

    o.Add_ret(c),

    o.Add_ret(a).Add_ret(b),

    o.Add_ret(a).Add_ret(c),

    o.Add_ret(b).Add_ret(c),

    o.Add_ret(a).Add_ret(b).Add_ret(c),

    }



    for i := 0; i < 8; i++ {

    for j := i + 1; j < 8; j++ {

    ca.Line(ps[i], ps[j], col)



    }

    }

    }



    It draws a parallelepiped - using the Line method that canvas.Canvas3type_drawable
    must implement.
    In a simple single screen example the Line method just draws one
    parallelepiped from one projection.
    But in the extended case it draws the object from 3 viewpoints etc. The
    target drawn to is a different struct type - hence the need to use an
    interface receiver (The Add_ret methods etc are just some vector math
    helper functions)
    Based on this description, this feels like a job for a command buffer. I.e.
    instead of pushing each shape through the interfaces, you create a separate
    structure, command buffer, stream, bytes... something like that. A
    collection of ordered primitives/commands that the
    canvas/transformations understand. I.e. each shape writes to a buffer its
    representation. This should be faster and simpler in codewise.

    + Egon

    --
    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.
  • Egon at Jul 5, 2015 at 2:36 pm
    BTW, I kept thinking how to implement command buffer in Go efficiently and
    this is what I came up with:

    https://github.com/egonelbre/exp/tree/master/zerostream *(The repetitive
    code for iterator can be generated/)*

    *WARNING: lots of unsafe code in it.*

    It tries its best to avoid allocation and to keep everything linear,
    although I haven't fully profiled/debugged to be sure about the performance
    gains.

    It currently can read/write ~300,000 commands per ms, which isn't ideal,
    but I think it's pretty good.

    The usage of iterator could be improved, i.e. instead of making the getter
    do the step a separate method should do it instead.
    Also add some assertions for debug release, so that you can ensure you are
    not mis-reading the values.

    You then can have transformation that builds up a new stream or
    alternatively modifies the stream in place.
    Eventually give the whole stream to the renderer and let it slurp through
    the stream.

    Anyways as a proof of concept works quite well.

    + Egon

    --
    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
postedJun 27, '15 at 8:15a
activeJul 5, '15 at 2:36p
posts15
users4
websitegolang.org

People

Translate

site design / logo © 2021 Grokbase