Sunday, May 19, 2024
HomeGolangHow come reflection is the one strategy to DRY this code, and...

How come reflection is the one strategy to DRY this code, and can one thing be carried out about it? – Technical Dialogue


With foundational background in dynamically typed programming languages, I’m struggling to return to phrases with static typing.

Static typing itself would have been high-quality if it wasn’t inflicting the necessity to both violate the DRY precept, or use performance-costly reflection in sure conditions. Like on this one:

Say we have to write a video stream parser. Video binary knowledge is comprised of frames, every having a kind, a sure header construction and a payload. My CCTV cameras produce streams of 5 body sorts (video key, video non-key, audio, nonetheless image and data), however for simplicity let’s take into account solely 2, simplified sorts. Full instance with some pretend knowledge:

bundle predominant
import (
    "fmt"
    "encoding/binary"
    "bytes"
    "io"
)

sort Kind byte

const (
    Video  Kind = 0xFC
    Audio   Kind = 0xFA
)

var HMap = map[Type]string {
    Video:   "Video",
    Audio:   "Audio",
}

sort CommonHeader struct {
    Kind      Kind
}

sort Header interface {
    GetLength() int
}

sort HeaderVideo struct {
    Width       uint16
    Peak      uint16
    Size      uint32
}

sort HeaderAudio struct {
    SampleRate  uint16
    Size      uint16
}

func (h HeaderVideo) GetLength() int {
    return int(h.Size)
}

func (h HeaderAudio) GetLength() int {
    return int(h.Size)
}

var TMap = map[Type]func() Header {
    Video:     func() Header { return &HeaderVideo{} },
    Audio:     func() Header { return &HeaderAudio{} },
}

func predominant() {
    knowledge := bytes.NewReader([]byte{0xFC, 0x80, 0x07, 0x38, 0x04, 0x02, 0x00, 0x00, 0x00, 0xFF, 0xAF, 0xFA, 0x10, 0x00, 0x01, 0x00, 0xFF})
    var cHeader CommonHeader
    for {
        err := binary.Learn(knowledge, binary.LittleEndian, &cHeader)
        if err != nil {
            break
        }
        fmt.Println(HMap[cHeader.Type])
        body := TMap[cHeader.Type]()
        binary.Learn(knowledge, binary.LittleEndian, body)
        fmt.Println(body)
        payload := make([]byte, body.GetLength())
        io.ReadFull(knowledge, payload)
        fmt.Println(payload)
    }
}

See — precisely the identical implementation of the GetLength() methodology must be repeated for every body sort. Not an enormous deal I hear you say. Certainly, on this case. Even when repeated 5 instances in the actual code (5 body sorts). However the reality stays: the code can’t be DRYed in precept. Until utilizing reflection:

func GetLength(body any) int {
    return int(mirror.ValueOf(body).Elem().FieldByName("Size").Uint())
}

var TMap = map[Type]func() any {
    Video:     func() any { return &HeaderVideo{} },
    Audio:     func() any { return &HeaderAudio{} },
}

So, I’m simply questioning: how do the present authors of Go see this drawback? Is it recognised? Will it’s tackled in some unspecified time in the future? Or do they not see it an issue in any respect?

RELATED ARTICLES

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Most Popular

Recent Comments