Skip to content

Struct Field Assignment

Harneet supports Go-like direct struct field assignment, allowing you to access and modify struct fields using dot notation.

Basic Syntax

Field Access

Field Access
1
2
3
var person = Person{Name: "Alice", Age: 30}
var name = person.Name    // Access field value
var age = person.Age      // Access field value

Field Assignment

Field Assignment
person.Name = "Bob"       // Assign new value to field
person.Age = 25           // Assign new value to field

Zero Value Initialization

Structs can be declared without initialization, and all fields will be set to their zero values:

Zero Values
type Person struct {
    Name string
    Age int
    Active bool
}

function main() {
    var p Person              // Zero value initialization
    // p.Name = ""            (empty string)
    // p.Age = 0              (zero integer)
    // p.Active = false       (false boolean)

    // Assign fields directly
    p.Name = "Alice"
    p.Age = 30
    p.Active = true
}

Nested Field Assignment

Harneet supports nested field assignment on chained dotted receivers.

Nested Assignment
1
2
3
4
5
6
7
8
9
type Address struct { city string; zip int }
type Person struct { name string; addr Address }

function main() {
    var p = Person{name: "Alice", addr: Address{city: "SF", zip: 94105}}
    p.addr.city = "LA"
    p.addr.zip = 90001
    fmt.Println(p) // Person{name: Alice, addr: Address{zip: 90001, city: LA}}
}

Method Calls on Fields

You can call methods directly on field values without introducing intermediates.

Method Calls on Fields
1
2
3
4
5
6
7
8
9
type Address struct { city string }
function (a Address) toString() string { return a.city }

type Person struct { name string; addr Address }

function main() {
    var p = Person{name: "Alice", addr: Address{city: "Paris"}}
    fmt.Println(p.addr.toString()) // Paris
}

Compile-time Validation of Dotted Chains

The type checker validates receivers for dotted access at compile-time:

  • Struct receiver required: Each . step must have a struct-like receiver (struct or user-defined struct type).
  • Invalid receiver error: Accessing a field or calling a method on a non-struct produces a type error.

Examples:

Reference Semantics
type Person struct { name string }

var p = Person{name: "A"}
var n = 42

// ❌ Error: cannot access field name on type int
n.name = "x"

// ❌ Error: cannot call method toString on type int
n.toString()

// ✅ OK: structs and nested fields are validated step-by-step
p.name = "Bob"

Zero Values by Type

Type Zero Value
string "" (empty string)
int 0
float64 0.0
bool false
map[K]V None (must be initialized)
Custom structs All fields set to their zero values

Complete Examples

Basic Field Operations

Basic Operations
type Person struct {
    Name string
    Age int
    Active bool
}

function main() {
    // Method 1: Zero value initialization + field assignment
    var p1 Person
    p1.Name = "Alice"
    p1.Age = 30
    p1.Active = true

    // Method 2: Struct literal initialization
    var p2 = Person{Name: "Bob", Age: 25, Active: false}

    // Field access
    fmt.Printf("p1.Name: %s\n", p1.Name)
    fmt.Printf("p2.Age: %d\n", p2.Age)

    // Field modification
    p2.Age = p2.Age + 1
    p2.Active = !p2.Active
}

Multiple Struct Instances

Multiple Instances
type Point struct {
    X int
    Y int
}

function main() {
    var p1 Point
    var p2 Point

    // Each instance is independent
    p1.X = 10
    p1.Y = 20

    p2.X = 30
    p2.Y = 40

    fmt.Printf("p1: (%d, %d)\n", p1.X, p1.Y)  // (10, 20)
    fmt.Printf("p2: (%d, %d)\n", p2.X, p2.Y)  // (30, 40)
}

Field Assignment in Functions

Functions with Structs
type Rectangle struct {
    Width int
    Height int
}

function setDimensions(rect Rectangle, w int, h int) {
    rect.Width = w
    rect.Height = h
}

function main() {
    var r Rectangle
    setDimensions(r, 100, 50)

    fmt.Printf("Rectangle: %dx%d\n", r.Width, r.Height)
}

Export Rules (Go-like Convention)

Field visibility follows Go-like export conventions:

Export Rules
1
2
3
4
5
6
type User struct {
    Name string    // Exported (accessible from other packages)
    age int        // Unexported (package-private)
    Email string   // Exported
    password string // Unexported
}
  • Exported fields: Start with uppercase letter, accessible from other packages
  • Unexported fields: Start with lowercase letter, only accessible within the same package

Comparison with Other Languages

Go Similarity

// Go
type Person struct {
    Name string
    Age  int
}

function main() {
    var p Person
    p.Name = "Alice"
    p.Age = 30
}
Harneet Syntax
// Harneet (nearly identical)
type Person struct {
    Name string
    Age int
}

function main() {
    var p Person
    p.Name = "Alice"
    p.Age = 30
}

Differences from JavaScript

1
2
3
4
// JavaScript - dynamic typing
var person = {};
person.name = "Alice";    // Can add fields dynamically
person.age = 30;
Static Typing
1
2
3
4
5
6
7
8
// Harneet - static typing
type Person struct {
    Name string
    Age int
}
var person Person         // Must declare struct type first
person.Name = "Alice"     // Only predefined fields allowed
person.Age = 30

Best Practices

  1. Use descriptive field names: UserName instead of Name when context matters
  2. Follow export conventions: Uppercase for public fields, lowercase for private
  3. Initialize before use: Always ensure structs are properly initialized
  4. Zero value awareness: Understand what zero values mean for your use case
  5. Prefer struct literals: Use Person{Name: "Alice", Age: 30} when you have all values

Error Cases

Error Cases
type Person struct {
    Name string
    Age int
}

function main() {
    var p Person

    // ✅ Valid operations
    p.Name = "Alice"
    var name = p.Name

    // ❌ Invalid operations
    // p.InvalidField = "value"  // Error: field doesn't exist
    // var x = p.Name.InvalidMethod()  // Error: strings don't have methods
}

Integration with Other Features

With Maps

Structs with Maps
type Config struct {
    Settings map[string]string
}

function main() {
    var cfg Config
    cfg.Settings = {"theme": "dark", "lang": "en"}

    var theme = cfg.Settings["theme"]
}

With Arrays

Structs with Arrays
type Team struct {
    Members []string
}

function main() {
    var team Team
    team.Members = ["Alice", "Bob", "Charlie"]

    var firstMember = team.Members[0]
}

With Functions

Structs with Functions
type Calculator struct {
    Result float64
}

function (c Calculator) add(x float64) {
    c.Result = c.Result + x
}

function main() {
    var calc Calculator
    calc.add(10.5)
    fmt.Printf("Result: %f\n", calc.Result)
}

Current Limitations

  1. Field address taking: Cannot take addresses of fields (no pointers yet)

Future Enhancements

  • Struct embedding and inheritance
  • Field tags and metadata
  • Pointer semantics for reference types