Skip to content

code styling #4

Open
Open
@mattetti

Description

I'd like to discuss code styling for a minute. It would be good to agree on a general approach of the code we'd like to write. Here are some examples, I'd like to hear more about what you think

##Code styling

Embedded type and optimized struct sizes

type Format struct {
	SampleRate uint32
	Channels   int16
}

type Buffer32 struct {
	Format
	Data []float32
}

vs pointers and convenient field types

type Format struct {
	SampleRate int
	Channels   int
}

type Buffer32 struct {
	Format *Format
	Data []float32
}

Convenient but straight forward constructor

func NewBuffer32(format Format, sampleCount int) *Buffer32 {
	return &Buffer32{
		Format: format,
		Data:   make([]float32, sampleCount, sampleCount),
	}
}

vs DIY approach. (note that in this code, the sample count should probably
multiple by the number of channels which is an easy thing to forget.)

&Buffer32{ 
    Format: format,
	Data:   make([]float32, sampleCount),
}

Explicit, manually, duplicated functions

func (buffer *Buffer32) Process32(output *Buffer32) error {
	// stuff
	return nil
}

func (buffer *Buffer64) Process64(output *Buffer64) error {
    // stuff
    return nil
}

vs interface and type switching

    func Process(buf1, buf2 Buffer) error {
        switch t := t.(type) {
        *Buffer32:
            // some stuff
        *Buffer64:
            // some other stuff
        }
        return nil
    }

vs using go generate for any functions implemented the same way in float32 and 64

I personally like:

2: I don't think the convenience of a having a field in a type we can easily manipulate trumps the memory size gain. Plus using a pointer would allow us to provide predefined formats.

3: Constructors are often convenient, especially as entry points and when the setup isn't trivial. This example is a good example since it was was written by hand and technically has a bug. This bug would be mitigated by a constructor. It does come at a price of a bigger API and potentially surprising behaviors.

Finally 5: It might be a bit of a pain at first but it works better with code completion (easier for people not knowing the API), it can be optimized (custom logic and/or SIMD) but can be the source of more bugs (fix something on the float32 side but not float64 for instance). 7 (code generation) is nice but it always feels a bit clunky to have to move things outside of the code generation path because of some edge cases.

@egonelbre @kisielk @nigeltao what do you think?

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions