u/VastDesign9517

▲ 10 r/golang

Golang Slice Help (for a C guy)

I’m trying to get better with Go slices, and I’m having trouble building the right mental model.

When I learn a new language, I usually implement a deck of cards to practice things like traversal, initialization, and shuffling. Right now I’m implementing Fisher-Yates shuffle.

In C, I would write something like this:

void shuffle(int *array, int n) {
  if (n > 1) {
  srand(time(NULL)); 

  for (int i = n - 1; i > 0; i--) { 
    // Pick a random index from 0 to i 
      int j = rand() % (i + 1);
 
      //Swap array[i] with array[j]
         int temp = array[i];
         array[i] = array[j]; 
         array[j] = temp; 
    }

  }
}

This makes sense to me because I can clearly see the temporary variable and the swap.
Now Go's turn

func (d *Deck) Shuffle() {
for i := len(d.Cards) - 1; i > 0; i-- {
  j := rand.IntN(i + 1)
  d.Cards[i], d.Cards[j] = d.Cards[j], d.Cards[i]
  }
}

The part that confuses me is this line:

d.Cards[i], d.Cards[j] = d.Cards[j], d.Cards[i]

I understand that d.Cards is a slice, and that assigning to d.Cards[i] mutates the underlying array. But I don’t understand how this swap works without a temporary variable?

Is Go evaluating the right-hand side first, then assigning both values to the left-hand side? if so is slices the only place golang evaluates right side expressions first?

Also, for people who came from C/C++/Java/C#, did Go slices feel strange at first? Did the mental model eventually click?

reddit.com
u/VastDesign9517 — 21 hours ago
▲ 7 r/golang

C# developer trying to understand how to approach to reusable behavior

Hello, I am a C# developer trying to get better at Go, and I am trying to understand the idiomatic way to handle reusable behavior on small domain types.

In C#, I would probably reach for extension methods or generic abstractions. In Go, I am not sure what the right mental model is.

Here is the kind of problem I keep running into.

I receive JSON payloads where many fields come in as strings, but in my domain they are not all “just strings.” For example:

type Cycles string
type CycleCount string
type WorkOrder string
type MachineNumber string

I like defining these as separate types because it makes my validation/transformation code more explicit. A Cycles value is not the same concept as a WorkOrder, even if both are represented as strings in the incoming JSON.

For example, I may want behavior like this:

type Cycles string

func (c Cycles) IsEmpty() bool {
return string(c) == ""
}

func (c Cycles) IsPresent() bool {
return string(c) != ""
}

func (c Cycles) ToInt() (int, error) {
value, err := strconv.Atoi(string(c))
  if err != nil {
    return 0, &ParseError{
    Field: "cycles",
    Value: string(c),
    Err:   err,}
  }
return value, nil
}

func (c Cycles) IsPositive() (bool, error) {
value, err := c.ToInt()
  if err != nil {
    return false, err
  }
return value > 0, nil
}

This works, but the issue is that I end up writing almost the same methods over and over for many string-backed types.

So my first question is:

Is defining small domain types like type Cycles string and putting behavior on them a reasonable Go approach, or am I already thinking about this wrong?

The approaches I have considered are:

1. Struct embedding

Something like:

type StringValue struct {
raw string
}

func (s StringValue) IsEmpty() bool {
return s.raw == ""
}

func (s StringValue) IsPresent() bool {
return s.raw != ""
}

func (s StringValue) String() string {
return s.raw
}

type NumericString struct {
raw string
}

func (n NumericString) ToInt() (int, error) {
return strconv.Atoi(n.raw)
}

func (n NumericString) IsPositive() (bool, error) {
value, err := n.ToInt()
  if err != nil {
    return false, err
}
return value > 0, nil
}

Then maybe:

type Cycles struct {
StringValue
NumericString
}

But this seems awkward because my JSON payload is shaped like this:

{
  "cycles": "100"
}

And I want this:

type Payload struct {
Cycles Cycles `json:"cycles"`
}

If Cycles is a struct, then I think I need custom JSON marshaling/unmarshaling just to preserve the simple JSON shape. That feels like it may create more boilerplate than it removes.

2. Interfaces plus free functions

I also considered interfaces like:

type StringConverter interface {
ToInt() (int, error)
}

func IsPositive(v StringConverter) (bool, error) {
n, err := v.ToInt()
  if err != nil {
  return false, err
  }
 return n > 0, nil
}

Then each domain type could implement ToInt().

That seems better than a large validator hierarchy, but I still have to write ToInt() for every type.

I also started thinking about larger validator-style interfaces, but that quickly started to feel like I was forcing a C#/OO design into Go.

3. Generics with a type constraint

This seems like the most promising option so far:

// package name here is important
package validation

type StringNumeric interface {
~string
}

func ToInt[T StringNumeric](field string, v T) (int, error) {
n, err := strconv.Atoi(string(v))
  if err != nil {
    return 0, &ParseError{
    Field: field,
    Value: string(v),
    Err:   err,}
  }
  return n, nil
}

func IsPositive[T StringNumeric](field string, v T) (bool, error) {
  n, err := ToInt(field, v)
    if err != nil {
      return false, err
    }
  return n > 0, nil
}

Then:

type Cycles string
type CycleCount string

ok, err := IsPositive("cycles", Cycles("100"))
ok, err = IsPositive("cycleCount", CycleCount("17"))

This seems like it reduces the boilerplate the most, but it also loses the method-call style:

cycles.IsPositive()

and becomes:

validation.IsPositive("cycles", cycles)

Maybe that is just the Go way, and I need to get used to packages plus functions instead of extension methods.

What I am trying to understand

I am not trying to build a framework for the sake of building a framework. I am a solo developer and I am trying to avoid writing the same validation/conversion methods for dozens of string-backed JSON fields.

What is the idiomatic Go approach here?

Should I:

  1. Keep the domain types as type Cycles string, type WorkOrder string, etc.
  2. Use generic helper functions over ~string for common validation/conversion behavior.
  3. Only add methods to the domain type when the behavior is truly domain-specific.
  4. Avoid struct embedding unless I specifically need stronger invariants or custom JSON behavior.

Or is there another Go pattern I am missing?

reddit.com
u/VastDesign9517 — 7 days ago
▲ 62 r/golang

Good morning guys,

So I spent about a year in golang it was my first serious language that I studied and tried and really wanted to master.

I never felt like I could identify how to build a program with it? it didnt feel object oriented. It didnt feel like functional. my programs I built were for orchrestrating a Oracle -> Postgres + running sql procedures to orchrestrate a datawarehouse

and I made a web server to run internal reporting websites.

Never in that language did I feel like the language starting unlocking this giant productivity boost. In C# I feel like Generics I spent a moment building myself this tool that I can save myself so much work on.

In C# I had rich domain types that help me map out my actual business and it felt like every day I program I unmapped the fog of my company.

In C# it felt like it wanted to help me solve something bigger then itself and I am building the toolkit.

but in golang. I solve the problem It felt like alot of code, it felt like ugly syntax. It felt like because I solved a problem and not a domain the interfaces I dont see how that helped me.

are my problems not big enough for golang? am In the wrong domain,

I want to love golang so badly. But man am I burnt from it and upset with myself for not getting it after a year.

"Simple language" yet I feel like a giant idiot.

If you guys can help me see something I'm missing that is this productivity multiplier people are talking about please show me.

my fear is people feel productive compared to C++ and from a system programming perspective it is productive.

is the right take away that Go is productive for infrastructure and I/O heavy services, and C# is productive for domain-rich business logic and I have been using the wrong tool for the job?

reddit.com
u/VastDesign9517 — 23 days ago