Examples
This section provides examples of Ziv code to help you get started with the language. Each example demonstrates a specific feature or concept of Ziv and includes an explanation of the code.
Table of Contents
- Hello, World!
- Basic Calculator
- Fibonacci Sequence
- List Operations
- Error Handling
- Custom Error Types
- Modules and Extensions
- Classes and Objects
- Concurrency
- Parallel Processing
- File I/O
- Networking
- Command-Line Arguments
- Environment Variables
- JSON Parsing
- Regular Expressions
- Unit Testing
- Context Managers
- Metaprogramming
- Custom Attributes
- Decorators
- Generics
- Enums
- Option Type
- Error Handling with Option Type
- Standard Library
Hello, World!
The classic "Hello, World!" program is a simple example that demonstrates how to print text to the console. Here is the Ziv code for the "Hello, World!" program:
fn main():
print("Hello, World!")
In this example, we define a function called main
that prints the text "Hello, World!" to the console using the print
function. The print
function is a built-in function in Ziv that outputs text to the standard output.
To run this program, save the code to a file with a .ziv
extension (e.g., hello.ziv
) and use the Ziv interpreter to execute the file:
zivc hello.ziv
This will compile the Ziv code and generate an executable file that you can run to see the output "Hello, World!" printed to the console.
Basic Calculator
This example demonstrates how to create a simple calculator program in Ziv that can perform basic arithmetic operations. Here is the Ziv code for the basic calculator program:
fn add(a: int, b: int) -> int:
return a + b
fn subtract(a: int, b: int) -> int:
return a - b
fn multiply(a: int, b: int) -> int:
return a * b
fn divide(a: int, b: int) -> int:
if b == 0:
error("Division by zero is not allowed")
return a / b
fn main():
num1: int = 10
num2: int = 5
print("Addition: ", add(num1, num2)) # Output: 15
print("Subtraction: ", subtract(num1, num2)) # Output: 5
print("Multiplication: ", multiply(num1, num2)) # Output: 50
print("Division: ", divide(num1, num2)) # Output: 2
In this example, we define four functions for performing basic arithmetic operations: add
, subtract
, multiply
, and divide
. These functions take two integer arguments and return the result of the corresponding operation. The divide
function also includes a check to prevent division by zero.
Fibonacci Sequence
The Fibonacci sequence is a series of numbers in which each number is the sum of the two preceding ones. This example demonstrates how to generate the Fibonacci sequence in Ziv using a recursive function. Here is the Ziv code for the Fibonacci sequence program:
fn fibonacci(n: int) -> int:
if n <= 1:
return n
return fibonacci(n - 1) + fibonacci(n - 2)
fn main():
num_terms: int = 10
for i: int in range(num_terms):
print(fibonacci(i))
In this example, we define a recursive function called fibonacci
that calculates the nth term of the Fibonacci sequence. The main
function generates and prints the first num_terms
terms of the Fibonacci sequence using a loop.
List Operations
This example demonstrates how to perform basic operations on lists in Ziv, such as creating a list, adding elements to a list, and iterating over a list. Here is the Ziv code for the list operations program:
fn main():
# Create a list of integers
numbers: list[int] = [1, 2, 3, 4, 5]
# Add an element to the list
numbers.append(6)
# Iterate over the list and print each element
for (num: int in numbers):
print(num)
# Output: 1 2 3 4 5 6
Error Handling
This example demonstrates how to handle errors in Ziv using the error
function. Here is the Ziv code for the error handling program:
fn read_file(file_path: string) -> string:
if file_path == "":
error("File path cannot be empty")
# Read the file
return "File content"
In this example, we define a function called read_file
that takes a file_path
argument. If the file_path
is empty, the function calls the error
function with an error message. This will terminate the program and print the error message to the console.
Custom Error Types
This example demonstrates how to define custom error types in Ziv to represent different kinds of errors in your programs. Custom error types allow you to create structured error messages with additional information and context, making it easier to handle and report errors in your code. Here is an example of defining custom error types in Ziv:
error DivisionByZero:
message: string
fn divide(a: int, b: int) -> int:
if b == 0:
throw DivisionByZero("Division by zero is not allowed")
return a / b
In this example, we define a custom error type DivisionByZero
with a message field to represent a division by zero error. We then define a function divide
that checks for a division by zero condition and throws a DivisionByZero
error with an error message if the condition is met. By using custom error types, you can provide more context and information about the error, making it easier to handle and report errors in your programs.
Modules and Extensions
This example demonstrates how to create and use modules and extensions in Ziv. Modules allow you to organize your code into reusable components, while extensions enable you to add new functionality to existing types. Here is an example of creating a module and an extension in Ziv:
-
Module:
math.ziv
# math.ziv module math version "1.0" fn add(a: int, b: int) -> int: return a + b fn subtract(a: int, b: int) -> int: return a - b end module
# main.ziv import math fn main(): result: int = math.add(1, 2) print(result) # Output: 3
-
Extension:
string_extensions.ziv
# string_extensions.ziv extension string version "1.0" fn is_palindrome(s: string) -> bool: return s == s.reverse() end extension
# main.ziv import string_extensions fn main(): text: string = "radar" if text.is_palindrome(): print("Palindrome") else: print("Not a palindrome")
In these examples, we define a module called math
that contains functions for basic arithmetic operations and an extension for strings that adds a is_palindrome
method. We then import and use these modules and extensions in the main
function.
Classes and Objects
This example demonstrates how to define classes and create objects in Ziv. Classes allow you to define custom data types with properties and methods, while objects are instances of classes that hold specific values. Here is an example of defining a class and creating objects in Ziv:
class Point:
private x: int
private y: int
public fn init(x: int, y: int):
self.x = x
self.y = y
public fn + (other: Point) -> Point:
return Point(self.x + other.x, self.y + other.y)
fn main():
p1: Point = Point()
p1.init(1, 2)
p2: Point = Point()
p2.init(3, 4)
p3: Point = p1 + p2
print(p3.get_x(), p3.get_y()) # Output: 4 6
In this example, we define a class called Point
with private properties x
and y
and a public init
method to initialize the object. We also define an overloaded +
operator to add two Point
objects together. In the main
function, we create two Point
objects p1
and p2
, initialize them with values, add them together, and print the result.
Concurrency
This example demonstrates how to create and run concurrent tasks in Ziv using the spawn
keyword. Concurrent tasks allow you to execute multiple operations simultaneously, improving performance and responsiveness. Here is an example of running concurrent tasks in Ziv:
fn task(id: int):
print("Task " + id + " started.")
// Simulate work with sleep
std.time.sleep(2)
print("Task " + id + " completed.")
fn main():
spawn(task, 1)
spawn(task, 2)
spawn(task, 3)
In this example, we define a function called task
that takes an id
argument and simulates work by sleeping for 2 seconds. In the main
function, we use the spawn
keyword to run three concurrent tasks with different IDs. The tasks will execute simultaneously, and the completion messages will be printed to the console.
Parallel Processing
This example demonstrates how to perform parallel processing in Ziv using the parallel
keyword. Parallel processing allows you to execute multiple operations concurrently across multiple cores, improving performance for CPU-bound tasks. Here is an example of parallel processing in Ziv:
fn calculate_sum(start: int, end: int) -> int:
sum: int = 0
for (i: int = start; i <= end; i = i + 1):
sum = sum + i
return sum
fn main():
parallel:
sum1: int = calculate_sum(1, 1000)
sum2: int = calculate_sum(1001, 2000)
sum3: int = calculate_sum(2001, 3000)
total_sum: int = sum1 + sum2 + sum3
print("Total sum: ", total_sum)
File I/O
This example demonstrates how to read and write files in Ziv using the std.fs
module. File I/O operations allow you to interact with files on the filesystem, such as reading data from files, writing data to files, and creating new files. Here is an example of file I/O in Ziv:
import std.fs
fn read_file(file_path: string):
file: std.fs.File =
std.fs.open(file_path, std.fs.Mode.READ)
if file.is_open():
content: string = file.read_all()
print(content)
file.close()
error("Failed to open file")
fn write_file(file_path: string, content: string):
file: std.fs.File =
std.fs.open(file_path, std.fs.Mode.WRITE)
if file.is_open():
file.write(content)
file.close()
error("Failed to open file")
fn main():
file_path: string = "example.txt"
content: string = "Hello, World!"
write_file(file, content)
read_file(file)
In this example, we define two functions read_file
and write_file
that read and write files, respectively. The main
function demonstrates how to write the text "Hello, World!" to a file called example.txt
and then read the contents of the file and print them to the console.
Networking
This example demonstrates how to perform networking operations in Ziv using the std.net
module. Networking operations allow you to interact with remote servers, send and receive data over the network, and create network clients and servers. Here is an example of networking in Ziv:
import std.net
fn fetch_url(url: string):
response: std.net.Response =
std.net.get(url)
if response.status_code == 200:
print(response.body)
error("Failed to fetch URL")
fn main():
url: string = "https://example.com"
fetch_url(url)
In this example, we define a function fetch_url
that fetches the contents of a URL using an HTTP GET request. The main
function demonstrates how to fetch the contents of the URL https://example.com
and print the response body to the console.
Command-Line Arguments
This example demonstrates how to access command-line arguments in Ziv using the std.args
module. Command-line arguments allow you to pass input parameters to a Ziv program when running it from the command line. Here is an example of accessing command-line arguments in Ziv:
import std.args
fn main():
args: list[string] = std.args.get_args()
for (arg: string in args):
print(arg)
In this example, we define the main
function that retrieves the command-line arguments using the std.args.get_args
function and prints each argument to the console. When running the Ziv program from the command line, you can pass arguments that will be printed by the program.
Environment Variables
This example demonstrates how to access environment variables in Ziv using the std.env
module. Environment variables allow you to store configuration settings and other information that can be accessed by Ziv programs. Here is an example of accessing environment variables in Ziv:
import std.env
fn main():
username: string = std.env.get("USERNAME")
if username != "":
print("Hello, ", username)
error("Username not found in environment variables")
In this example, we use the std.env.get
function to retrieve the value of the USERNAME
environment variable and print a greeting message to the console. If the USERNAME
environment variable is not found, the program will print an error message.
JSON Parsing
This example demonstrates how to parse JSON data in Ziv using the std.json
module. JSON parsing allows you to read and manipulate JSON data structures in Ziv programs. Here is an example of parsing JSON data in Ziv:
import std.json
fn main():
data: std.json.Value = std.json.parse(json_data)
name: string = data.get("name").as_string()
age: int = data.get("age").as_int()
print("Name: ", name)
print("Age: ", age)
In this example, we define the main
function that contains a JSON string representing a person's name and age. We use the std.json.parse
function to parse the JSON data into a Value
object and then extract the name and age values from the object and print them to the console.
Regular Expressions
This example demonstrates how to use regular expressions in Ziv using the std.regex
module. Regular expressions allow you to search for patterns in text data and perform string manipulation based on those patterns. Here is an example of using regular expressions in Ziv:
import std.regex
fn main():
text: string = "The quick brown fox jumps over the lazy dog"
pattern: string = "fox|dog"
matches: list[string] = std.regex.find_all(text, pattern)
for (match: string in matches):
print(match)
In this example, we define the main
function that contains a text string and a regular expression pattern to search for the words "fox" or "dog" in the text. We use the std.regex.find_all
function to find all matches of the pattern in the text and print each match to the console.
Unit Testing
This example demonstrates how to write unit tests in Ziv using the test
keyword. Unit testing allows you to verify the correctness of individual functions or modules by writing test cases that check the expected behavior of the code. Here is an example of writing unit tests in Ziv:
fn add(a: int, b: int) -> int:
return a + b
test "Addition":
assert(add(1, 2) == 3)
assert(add(0, 0) == 0)
assert(add(-1, 1) == 0)
fn main():
run_tests()
In this example, we define a function add
that performs addition and a test case for the add
function. The test case uses the assert
keyword to check the expected results of adding different numbers. The main
function calls the run_tests
function to execute all test cases defined in the program.
Context Managers
This example demonstrates how to use context managers in Ziv to manage resources and ensure proper cleanup. Context managers allow you to define a block of code that automatically handles resource allocation and deallocation, such as opening and closing files or database connections. Here is an example of using context managers in Ziv:
fn main():
using std.fs.open("example.txt", std.fs.Mode.WRITE) as file:
file.write("Hello, World!")
Metaprogramming
This example demonstrates how to use metaprogramming in Ziv to generate code dynamically at compile time. Metaprogramming allows you to write code that generates other code, enabling powerful abstractions and code transformations. Here is an example of metaprogramming in Ziv:
macro repeat(n: int, body: block):
for (i: int = 0; i < n; i = i + 1):
body
fn main():
repeat(3):
print("Hello, World!")
Custom Attributes
This example demonstrates how to define and use custom attributes in Ziv to annotate code elements with metadata. Custom attributes allow you to add additional information to functions, types, or variables that can be used by the compiler or other tools, without affecting the program's behavior. Here is an example of defining and using custom attributes in Ziv:
attribute deprecated:
message: string
level: string = "warning" # Default value
attribute dangerous:
message: string
level: string = "error" # Default value
@deprecated("This function is deprecated")
fn old_function():
# Function implementation
@dangerous("This function is dangerous", level: "error")
fn dangerous_function():
# Function implementation
fn main():
old_function() # Warning: This function is deprecated
dangerous_function() # Error: This function is dangerous
Decorators
This example demonstrates how to use decorators in Ziv to add behavior to functions or methods at runtime. Decorators allow you to wrap or modify the behavior of functions without changing their source code, enabling code reuse and separation of concerns. Here is an example of using decorators in Ziv:
fn uppercase_decorator(fn: fn() -> string) -> string:
result: string = fn()
return result.upper()
@uppercase_decorator
fn get_greeting() -> string:
return "hello"
fn main():
print(get_greeting()) # Output: HELLO
Generics
This example demonstrates how to use generics in Ziv to write reusable code that works with different types. Generics allow you to define functions, classes, or data structures that can operate on any type, providing flexibility and type safety. Here is an example of using generics in Ziv:
fn print_list<T>(items: list[T]) -> void:
for (item: T in items):
print(item)
In this example, we define a generic function print_list
that takes a list of items of any type T
and prints each item to the console. The function can be used with lists of integers, strings, or any other type, making it versatile and reusable.
Enums
This example demonstrates how to define and use enums in Ziv to represent a set of named constants. Enums allow you to define custom data types with a fixed set of values, making the code more readable and maintainable. Here is an example of using enums in Ziv:
enum Color:
RED
GREEN
BLUE
fn main():
color: Color = Color.RED
match color:
Color.RED => print("Red")
Color.GREEN => print("Green")
Color.BLUE => print("Blue")
In this example, we define an enum Color
with three constants RED
, GREEN
, and BLUE
. We create a variable color
of type Color
and use a match
expression to print the corresponding color name based on the value of the color
variable.
Option Type
This example demonstrates how to use the option type in Ziv to handle nullable values and avoid null pointer exceptions. The option type allows you to represent a value that may or may not be present, providing a safer and more expressive way to handle missing values. Here is an example of using the option type in Ziv:
fn divide(a: int, b: int) -> option[int]:
if b == 0:
return none
return some(a / b)
In this example, we define a function divide
that takes two integers a
and b
and returns an option[int]
value representing the result of dividing a
by b
. If b
is zero, the function returns none
to indicate a division by zero error. Otherwise, it returns some
with the result of the division.
Error Handling with Option Type
This example demonstrates how to use the option type for error handling in Ziv. By combining the option type with pattern matching, you can elegantly handle errors and missing values in a functional and concise way. Here is an example of error handling with the option type in Ziv:
fn parse_int(s: string) -> option[int]:
try:
return some(s.to_int())
return none
fn main():
num_str: string = "123"
match parse_int(num_str):
some(num) => print("Parsed number: ", num)
none => print("Failed to parse number")
# Output: Parsed number: 123
invalid_str: string = "abc"
match parse_int(invalid_str):
some(num) => print("Parsed number: ", num)
none => print("Failed to parse number")
# Output: Failed to parse number
In this example, we define a function parse_int
that attempts to parse a string s
into an integer using the to_int
method. If the parsing is successful, the function returns some
with the parsed integer value. If an error occurs during parsing, the function returns none
. In the main
function, we use pattern matching to handle the result of the parse_int
function and print the parsed number or an error message based on the result.
Standard Library
The Ziv standard library provides a rich set of modules and functions for common programming tasks, such as working with files, networking, data serialization, and more. You can explore the Ziv Standard Library Reference to learn more about the available modules and functions in the standard library.