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 |
|---|
| import fmt
import strings
import json
|
Comma-Separated Imports
| Comma-Separated Imports |
|---|
| import fmt, strings, json
import math, datetime, os
|
Import Aliases
| Import Aliases |
|---|
| 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 |
|---|
| // 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:
| 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 |
|---|
| // 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 |
|---|
| // 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 |
|---|
| 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
| 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
| 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
- Look for directory with matching name
- Find
.ha files with matching package declaration - Load and evaluate package in isolated environment
- Make exported symbols available to importing module
Type Compatibility
Struct Type Matching
Module-qualified types are compatible with their base types:
| Type Matching |
|---|
| // 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:
| 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 |
|---|
| // 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 |
|---|
| // 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 |
|---|
| // 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 |
|---|
| // 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.