Skip to content

Import System

Harneet provides a comprehensive import system that supports both standard library modules and local Harneet packages, with Go-like syntax and modern features including relative imports and module-qualified types.

Standard Library Imports

Basic Import Syntax

Basic Imports
1
2
3
import fmt
import strings
import json

Comma-Separated Imports

Comma-Separated Imports
import fmt, strings, json
import math, datetime, os

Import Aliases

Import Aliases
1
2
3
import fmt as f
import strings as str
import "../mylib" as mylib

Local Package Imports

Relative Imports

Harneet supports relative imports using ../ and ./ syntax, similar to modern module systems:

Relative Imports
1
2
3
4
5
6
7
8
// Import from parent directory
import "../mylib" as mylib

// Import from current directory
import "./utils" as utils

// Import from subdirectory
import "./helpers/validation" as validate

Package Structure

Local packages must follow Go-like conventions:

1
2
3
4
5
6
project/
├── main.ha              # package main
├── mylib/
│   └── lib.ha          # package mylib
└── utils/
    └── helpers.ha      # package utils

Package Declaration

Each Harneet file must start with a package declaration:

Package Declaration
// mylib/lib.ha
package mylib

// Exported struct type (starts with uppercase)
type User struct {
    name string
    age int
}

// Exported variable
var DefaultAge int = 21

// Exported function
function MakeDefaultUser(name string) User {
    return User{name: name, age: DefaultAge}
}

Module-Qualified Types

Type Annotations

Use imported types in variable declarations, function parameters, and return types:

Type Annotations
package main
import "../mylib" as mylib

function main() {
    // Module-qualified type in variable annotation
    var user mylib.User = mylib.MakeDefaultUser("Alice")

    // Module-qualified type in function parameter
    function processUser(u mylib.User) {
        fmt.Printf("Processing user: %s\n", u.name)
    }

    processUser(user)
}

Struct Literals

Create instances using module-qualified struct literals:

Struct Literals
1
2
3
4
5
6
7
8
// Direct struct literal with module qualification
var user mylib.User = mylib.User{name: "Bob", age: 33}

// Struct literal in typed array
var users = mylib.User[2]{
    mylib.User{name: "Carol", age: 25},
    mylib.User{name: "Dave", age: 30},
}

Typed Arrays

Use module-qualified types in typed array declarations:

Typed Arrays
1
2
3
4
5
6
7
8
9
// Typed array with module-qualified element type
var userArray = mylib.User[3]{
    mylib.User{name: "Alice", age: 25},
    mylib.User{name: "Bob", age: 30},
    mylib.User{name: "Charlie", age: 35},
}

// Access array length
var count = len(userArray)  // Returns: 3

Export Rules

Harneet follows Go-like export rules:

Exported Names

  • Uppercase first letter: Exported (public)
  • Lowercase first letter: Unexported (private)
Export Examples
package mylib

// Exported (public) - can be imported
type User struct { ... }        // ✅ Exported
var DefaultAge int = 21         // ✅ Exported  
function MakeUser() User { ... } // ✅ Exported

// Unexported (private) - cannot be imported
type userInternal struct { ... }     // ❌ Private
var internalConfig string = "..."    // ❌ Private
function validateUser() bool { ... } // ❌ Private

Struct Fields

Struct Fields
1
2
3
4
5
type User struct {
    Name string    // ✅ Exported field
    Age int        // ✅ Exported field
    id string      // ❌ Private field
}

Multi-File Main Packages

Directory Execution

Execute all .ha files in a directory as a single package main:

# Execute all .ha files in the app directory
harneet ./examples/packages/app

File Structure

1
2
3
4
app/
├── main.ha      # package main
├── helpers.ha   # package main  
└── config.ha    # package main

All files are combined into a single program execution context.

Complete Example

Project Structure

1
2
3
4
5
examples/packages/
├── app/
│   └── main.ha
└── mylib/
    └── lib.ha

Library Package (mylib/lib.ha)

Library Package
package mylib

// Exported struct type
type User struct {
    name string
    age int
}

// Exported variables
var DefaultAge int = 21
var Version string = "v1.0.0"

// Exported constructor function
function MakeDefaultUser(name string) User {
    return User{name: name, age: DefaultAge}
}

// Exported utility function
function Greet(name string) string {
    return "Hello " + name
}

Main Application (app/main.ha)

Main Application
package main

import fmt
import "../mylib" as mylib

function main() {
    fmt.Println("Testing module-qualified types and relative imports")

    // Use module-qualified type in variable annotation
    var u mylib.User = mylib.MakeDefaultUser("Alice")
    fmt.Println("DefaultAge:")
    fmt.Println(mylib.DefaultAge)
    fmt.Println("Version:")
    fmt.Println(mylib.Version)

    // Struct literal with module-qualified type
    var v mylib.User = mylib.User{name: "Bob", age: 33}

    // Typed array literal with module-qualified struct element type
    var arr = mylib.User[2]{
        mylib.User{name: "Carol", age: 10},
        mylib.User{name: "Dave", age: 20},
    }

    // Call exported function
    var message = mylib.Greet("Gagan")
    fmt.Println(message)

    fmt.Println("User u:")
    fmt.Println(u)
    fmt.Println("User v:")
    fmt.Println(v)
    fmt.Println("arr length:")
    fmt.Println(len(arr))
}

main()

Execution

$ harneet examples/packages/app
Testing module-qualified types and relative imports
DefaultAge:
21
Version:
v1.0.0
Hello Gagan
User u:
User{age: 21, name: Alice}
User v:
User{name: Bob, age: 33}
arr length:
2

Import Resolution

Standard Library

  • Resolved from built-in stdlib modules
  • Examples: fmt, strings, json, math, os

Relative Imports

  • ../package - Import from parent directory
  • ./package - Import from current directory
  • ./sub/package - Import from subdirectory

Package Discovery

  1. Look for directory with matching name
  2. Find .ha files with matching package declaration
  3. Load and evaluate package in isolated environment
  4. Make exported symbols available to importing module

Type Compatibility

Struct Type Matching

Module-qualified types are compatible with their base types:

Type Matching
1
2
3
4
5
6
7
// These are compatible:
var expected mylib.User = ...
var actual User = ...  // Base type from same module

// Type checker allows assignment between:
// - mylib.User ↔ User (when from same module)
// - mylib.User ↔ STRUCT (runtime struct objects)

Error Handling

Clear error messages for import and type issues:

1
2
3
Error: Cannot execute non-main package 'mylib'. Only 'package main' is executable.
Error: Missing package declaration. The first non-comment line must be 'package <name>'.
Error: variable 'u' type mismatch: cannot assign STRUCT to mylib.User

Best Practices

1. Package Organization

Package Organization
1
2
3
4
5
6
7
8
9
// Good: Clear package structure
project/
├── main.ha           # Main application
├── models/
│   └── user.ha      # User-related types
├── services/
│   └── api.ha       # API services
└── utils/
    └── helpers.ha   # Utility functions

2. Export Conventions

Export Conventions
1
2
3
4
5
6
7
8
// Good: Clear export intentions
type User struct { ... }        // Exported type
var DefaultConfig = { ... }     // Exported variable
function NewUser() User { ... } // Exported constructor

type userImpl struct { ... }    // Private implementation
var cache = { ... }             // Private cache
function validate() bool { ... } // Private helper

3. Import Aliases

Import Alias Best Practices
1
2
3
4
5
6
7
8
// Good: Clear, meaningful aliases
import "../models/user" as userModel
import "../services/api" as apiService
import "../utils/validation" as validate

// Avoid: Unclear or conflicting aliases
import "../models/user" as u  // Too short
import "../services/api" as user  // Confusing

4. Type Usage

Type Usage
1
2
3
4
5
6
// Good: Explicit type annotations for clarity
var user userModel.User = userModel.NewUser("Alice")
var users []userModel.User = userModel.LoadUsers()

// Good: Module-qualified constructors
var config apiService.Config = apiService.DefaultConfig()

Integration with Standard Library

The import system works seamlessly with all standard library modules:

Standard Library Integration
import fmt, json, cast
import "../models" as models

function processData(jsonStr string) models.User {
    var data, err = json.Unmarshal(jsonStr)
    if err != None {
        fmt.Printf("JSON error: %s\n", err)
        return models.User{}
    }

    var name, _ = cast.ToString(data["name"])
    var age, _ = cast.ToInt(data["age"])

    return models.User{name: name, age: age}
}

This import system provides the flexibility of modern module systems while maintaining the simplicity and type safety that makes Harneet productive for both small scripts and larger applications.