- Fixed two bugs that prevented compilation of Golf program in some cases. The issues were introduced in version 265.
- Set proper permissions on pcre2* files for packaging
Sunday, March 2, 2025
Golf 273 released
Saturday, March 1, 2025
Web framework for C programming language
In extended mode, Golf is effectively a web framework for C programming language; read this for more about implications on memory safety.
Here's the example of using Golf as a web framework for C. In this case it's a simple C function to calculate the factorial of a a number. Then we'll expose this functionality in an equally simple web application.
mkdir -p c-for-web cd c-for-webCopied!

Create "fact" application ("-k"):
gg -k fact
Copied!

Save the following into a file "calc-fact.golf". This is the web service which will interact with web clients (such as browsers); it will also call the C function we'll create a bit further below:
extended-mode // extended mode in order to call C code %% /calc-fact public get-param par // get input parameter from URL string-number par to num // convert to number set-number result call-extended factorial(num, &result) // call C function // Output result @Factorial of <<p-out par>> is <<p-num result>> %%Copied!

Next, create C file "factorial.c". This is the C function we're calling from Golf code above:
#include "golf.h" // Compute factorial of f, and store result into res void factorial(gg_num f, gg_num *res) { *res = 1; gg_num i; for (i = 2; i <= f; i++) { *res *= i; } }Copied!

Monday, February 24, 2025
Make RPM package on Fedora and RedHat
To create a Golf installation package for Fedora or RedHat (or similar based on those, like Rocky), first get Golf source code. To do that, install git first:
sudo dnf install git
Then get Golf source code:
git clone https://github.com/golf-lang/golf.git
cd golf
For Redhat/Rocky/etc. install EPEL:
sudo dnf install epel-release
Next, install rpm-build package:
sudo dnf install rpm-build
On Fedora,
Sunday, February 23, 2025
DEB package on Ubuntu and Debian
If you'd like to create a Golf installation package for Ubuntu or Debian (or similar based on those), first get Golf source code. To do that, install git first:
sudo apt update
sudo apt install git
Then get Golf source code:
git clone https://github.com/golf-lang/golf.git
cd golf
Before you can create a package, you must first install Debian tools:
sudo apt update
sudo apt -y install devscripts equivs build-essential lintian
Next,
Golf 261 released
- Added Fedora spec file for building RPM packages, and for upcoming COPR builds on Fedora infrastructure cloud service.
- Fixed a compilation issue with RedHat regarding _GNU_SOURCE flag.
- Refactor Golf memory code for about 10% better performance in memory-access intensive applications.
Friday, February 21, 2025
34000 requests per second on a modest laptop
Create new directory for the Golf server and also for C API client:
mkdir -p srv-example cd srv-example mkdir -p clientCopied!

Create file "srv.golf" and copy this:
begin-handler /srv public silent-header @Hello world! end-handlerCopied!

Create Golf application server:
gg -k hello
Copied!

Build Golf application server (exclude client directory as it contains C API client):
gg -q --exclude-dir=clientCopied!

Start the application server (a single-process server in this case):
mgrg -w 1 helloCopied!

Next, go to C API client directory:
cd client
Copied!

Then create C file "cli.c" and copy this:
#include "gcli.h" int golf_client (gg_cli *req, char *connection, char *method, char *app_path, char *request, char *url_params); int golf_client (gg_cli *req, char *connection, char *method, char *app_path, char *request, char *url_params) { memset ((char*)req, 0, sizeof(gg_cli)); req->server = connection; req->req_method = method; req->app_path = app_path; req->req = request; req->url_params = url_params; return gg_cli_request (req); } void main () { int i; for (i = 0; i < 1000000; i++) { gg_cli req; int res = golf_client (&req, "/var/lib/gg/hello/sock/sock", "GET", "/hello", "/srv", "/"); if (res != GG_OKAY) printf("Request failed [%d] [%s]\n", res, req.errm); else printf("%s", gg_cli_data(&req)); gg_cli_delete(&req); } }Copied!

Compile the client:
gcc -o cli cli.c $(gg -i) -O3Copied!

Run it:
./cliCopied!

The result is "Hello world!" 1,000,000 times from each request invocation.
Wednesday, February 19, 2025
Golf 253 released
- Fixed a memory leak that happens in rare situations with internal memory reallocation.
- Improved performance with request memory management.
- Improved performance with queries (across all databases, PostgreSQL, MariaDB, SQLite) with reduced number of memory copies and memory allocations.
Sunday, February 16, 2025
Golf 247 released
- Fixed bug with lists, where if process-scoped, data retrieved with read-list statement may in some rare cases be inaccurate.
- About 2% speed-up in request execution, due to refactoring of memory cleanup at the end of each request.
Thursday, February 13, 2025
Golf 244 released
- This release brings much faster memory for large-data servers, for instance servers that hold millions of rows organized in trees, hashes etc. The change is about separating ordinary memory used by a request (such as variables) from the process-scoped memory (which can hold lots of data). The performance improvement is mostly in a high-load environments, for instance when there are tens of thousands of requests per second inserting, deleting or querying data.
Wednesday, February 12, 2025
Use C language API to talk to Golf Server
In this example, a Golf server will use a tree object to store key/value pairs, which can be added, queried and deleted for as long as the server is running (i.e. it's an in-memory database, or a cache server). Client will insert the key/value pairs, query and delete them.
To get started, create a directory for this example and position in it:
mkdir -p c-api cd c-apiCopied!

Save this into a file "srv.golf":
begin-handler /srv public silent-header do-once new-tree ind process-scope end-do-once get-param op get-param key get-param data if-true op equal "add" write-tree ind key (key) value data status st if-true st equal GG_ERR_EXIST @Key exists [<<p-out key>>] else-if @Added [<<p-out key>>] end-if else-if op equal "delete" delete-tree ind key (key) value val status st if-true st equal GG_ERR_EXIST @Not found [<<p-out key>>] else-if @Deleted, old value was [<<p-out val>>] end-if else-if op equal "query" read-tree ind equal (key) value val status st if-true st equal GG_ERR_EXIST @Not found, queried [<<p-out key>>] else-if @Value [<<p-out val>>] end-if end-if end-handlerCopied!

Create "index" application ("-k"):
Tuesday, February 11, 2025
Golf 241 released
- This release improves memory handling, which is now faster. Also, several issues with process-scoped memory, such as leaking in some cases, has been resolved.
- delete-string will now always delete ordinary (non process-scoped) memory if not referenced prior to deletion, otherwise memory is always released at the end of request. This strikes a good balance between the ability to delete memory while request is executing (if needed), and at the same time, have an automatic memory de-allocator and safety mechanism that's high-performance because it's very lightweight.
Saturday, February 8, 2025
Golf 231 released
- Fixed memory issue with long running server processes when using process-scoped memory with a tree object. The problem would in some situations utilize more memory than needed. This fixes the issue and improves performance.
- Option "--optimize-memory" has been removed from gg utility due to adding an overhead for the benefit that's generally proven negligible.
Tuesday, February 4, 2025
Golf package page on AUR for Arch Linux
Golf's AUR page is https://aur.archlinux.org/packages/golf
You can build a pacman package from it, and install Golf from that package (on this or other machines):
cd golf
makepkg -sirc
Sunday, February 2, 2025
Ubuntu apt package available for Golf
You can install Golf from precompiled binaries provided by Launchpad which is Ubuntu service that builds Golf directly from its github source code repo.
You would add Golf repo:
sudo add-apt-repository ppa:golf-lang/golf sudo apt update
And then install Golf with:
sudo apt install golf
You can then manage the package using standard Ubuntu apt tools.
Golf 210 released
- Added new "error-line" and "error-char" clauses in JSON parsing (json-doc statement) to produce the line number and the character within the line where error in parsing was detected.
- Fixed a build bug with missing 'stub_xml.o' file. This file is a part of upcoming XML parsing support and plays no role currently, but it prevented the build from being completed.
- Fixed issue with maximum length of source code line, which should be approx 8K.
- Added debian apt package build support (debian/control etc.)
Thursday, January 30, 2025
How to send email with Golf
Create directory for your application:
mkdir -p mail cd mailCopied!
Create "mail-sender" application:
gg -k mail-sender
Copied!
Copy the following code to file "mail.golf":
begin-handler /mail public // Get URL parameter get-param action if-true action equal "show_form" // Display HTML form @<h2>Enter email and click Send to send it</h2> @Note: 'From' field must be the email address from the domain of your server.<br/><br/> @<form action="<<p-path "/mail">>" method="POST"> @ <input type="hidden" name="action" value="submit_form"> @ <label for="from_mail">From:</label><br> @ <input type="text" name="from_mail" value=""><br> @ <label for="to_mail">To:</label><br> @ <input type="text" name="to_mail" value=""><br><br> @ <label for="subject_mail">Subject:</label><br> @ <input type="text" name="subject_mail" value=""><br><br> @ <label for="message">Message:</label><br> @ <textarea name="message" rows="3" columns="50"></textarea> @ <br/><br/> @ <input type="submit" value="Send"> @</form> else-if action equal "submit_form" // Get data from HTML form get-param from_mail get-param to_mail get-param message get-param subject_mail // Construct email message write-string msg @From: <<p-out from_mail>> @To: <<p-out to_mail>> @Subject: <<p-out subject_mail>> @ <<p-out message>> end-write-string // Send email exec-program "/usr/sbin/sendmail" args "-i", "-t" input msg status st // Check status of email sending if-true st not-equal GG_OKAY @Could not send email! else-if @Email sent! end-if @<hr/> else-if @Unrecognized action!<hr/> end-if end-handlerCopied!
The example uses
Tuesday, January 28, 2025
Fast JSON parser with little coding
You can iterate through this array and get names of JSON elements, examine if they are of interest to you, and if so, get the values. This typical scenario is how Golf's parser is built, since it uses a "lazy" approach, where values are not allocated until needed, speeding up parsing. That is the case in this example. The JSON document below is examined and only the names of the cities are extracted.
You can also store JSON elements into trees or hashes for future fast retrieval, or store them into a database, etc.
To get started, create a directory for this example and position in it:
mkdir -p json cd jsonCopied!

Save this JSON into a file "countries.json" - we will get the names of the cities from it:
{ "country": [ { "name": "USA", "state": [ { "name": "Arizona", "city": [ { "name" : "Phoenix", "population": 5000000 } , { "name" : "Tuscon", "population": 1000000 } ] } , { "name": "California", "city": [ { "name" : "Los Angeles", "population": 19000000 }, { "name" : "Irvine" } ] } ] } , { "name": "Mexico", "state": [ { "name": "Veracruz", "city": [ { "name" : "Xalapa-EnrÃquez", "population": 8000000 }, { "name" : "C\u00F3rdoba", "population": 220000 } ] } , { "name": "Sinaloa", "city": [ { "name" : "Culiac\u00E1n Rosales", "population": 3000000 } ] } ] } ] }Copied!

What follows is the code to parse JSON. We open a JSON file, process the document, check for errors, and then read elements one by one. We look for a key "country"."state"."city"."name" because those contains city names. Note use "no-enum" clause in json-doc (which is the Golf's JSON parser), so that element designations aren't showing (meaning we don't have [0], [1] etc. for arrays).
Save this code to "parse-json.golf":
begin-handler /parse-json public // Read the JSON file read-file "countries.json" to countries status st if-true st lesser-equal 0 @Cannot read file or file empty exit-handler -1 end-if // Parse JSON json-doc countries no-enum status st error-text et error-position ep to json // Check for errors in JSON document if-true st not-equal GG_OKAY @Error [<<p-out et>>] at [<<p-num ep>>] exit-handler -2 end-if // This is the JSON element we're looking for set-string city_name unquoted ="country"."state"."city"."name" // Read elements one by one - note you can then store them in a tree or hash for future fast searches start-loop // Read just a key read-json json key k type t // Exit if end of document if-true t equal GG_JSON_TYPE_NONE break-loop end-if // If matches key we're looking for, get the value, and output it if-true city_name equal k read-json json value v @Value [<<p-out v>>] @-------- end-if // Move on to the next JSON element read-json json next end-loop // Optionally delete JSON object, or it will be automatically deleted json-doc delete json end-handlerCopied!

Monday, January 27, 2025
Golf 191 released
- Fixed bugs in compilation when process-scoped types are not recognized in some cases.
- Fixed bug in JSON processing that could see in rare cases wrong data produced by parsing.
Sunday, January 26, 2025
Golf 184 released
- New "array" type has been added. This is a string array with a number key, ranging from 0 to the array's maximum size. Note that Golf array is flexible: you do not need to specify the array size, rather only it maximum possible size. The actual memory allocated is nominal and will vary based on the data you store in the array. Arrays can also be purged to reduce their size back to the nominal. Statements included are new-array, read-array, write-array and purge-array.
- Renamed index type to reflect its structure, and now it's "tree". So the statements like new-index, read-index etc. are now new-tree, read-tree etc.
- Renamed set type to reflect its structure, and now it's "hash". So the statements like new-set, read-set etc. are now new-hash, read-hash etc.
Saturday, January 18, 2025
Golf 171 released
- "Array" statements are now "set", so for example new-array is now new-set. This change is made to align the names of data structures better with their qualities and to make room for a new "array" structure that will be a direct-memory access structure. Please rename these statements in your code to be compatible with this and future versions.
- The limit for a number of subdirectories in file storage is now 64000, instead of previous 40000, significantly increasing the number of files that can be stored (theoretically by 240,000,000,000).
Tuesday, January 14, 2025
Golf 155 released
- Gliimly has been renamed to Golf. New web site is https://golf-lang.com and blog is at https://golf-lang.blogspot.com/
- Note in order to migrate to Golf you need to:
1. Uninstall Gliimly (using "sudo make uninstall" from its source code directory).
2. Install Golf (see https://golf-lang.github.io/install.html)
3. Rename all your source files to have .golf extension
4. Rebuild your project (gg -q) - File type for source files has changed from .gliimly to .golf
- Fixed longstanding issue with (sometimes) bad diagnostic output for erroneous source (meaning non-correct error reporting).
- Added "no-enum" clause in json-doc statement to produce keys for JSON values that do not include array enumeration.
Friday, January 3, 2025
What is application server?
What is an application server? It is a set of background resident processes. Each such process can be contacted via socket with a request, and it will provide a reply. An application server often sits behind a web server which accepts user requests, passes them to the application server, receives its reply and the passes this reply back to the user. This is a "reverse proxy" configuration. Note that this configuration, though typical, isn't a hard rule; end users can talk to an application server directly in some cases, such as on a secure local network.
Thursday, December 26, 2024
Encryption: ciphers, digests, salt, IV
Encryption is a method of turning data into an unusable form that can be made useful only by means of decryption. The purpose is to make data available solely to those who can decrypt it (i.e. make it usable). Typically, data needs to be encrypted to make sure it cannot be obtained in case of unauthorized access. It is the last line of defense after an attacker has managed to break through authorization systems and access control.
This doesn't mean all data needs to be encrypted, because often times authorization and access systems may be enough, and in addition, there is a performance penalty for encrypting and decrypting data. If and when the data gets encrypted is a matter of application planning and risk assessment, and sometimes it is also a regulatory requirement, such as with HIPAA or GDPR.
Data can be encrypted at-rest, such as on disk, or in transit, such as between two parties communicating over the Internet.
Here you will learn how to encrypt and decrypt data using a password, also known as symmetrical encryption. This password must be known to both parties exchanging information.
To properly and securely use encryption, there are a few notions that need to be explained.
A cipher is the algorithm used for encryption. For example, AES256 is a cipher. The idea of a cipher is what most people will think of when it comes to encryption.
A digest is basically a hash function that is used to scramble and lengthen the password (i.e. the encryption key) before it's used by the cipher. Why is this done? For one, it creates a well randomized, uniform-length hash of a key that works better for encryption. It's also very suitable for "salting", which is the next one to talk about.
The "salt" is a method of defeating so-called "rainbow" tables. An attacker knows that two hashed values will still look exactly the same if the originals were. However, if you add the salt value to hashing, then they won't. It's called "salt" because it's sort of mixed with the key to produce something different. Now, a rainbow table will attempt to match known hashed values with precomputed data in an effort to guess a password. Usually, salt is randomly generated for each key and stored with it. In order to match known hashes, the attacker would have to precompute rainbow tables for great many random values, which is generally not feasible.
You will often hear about "iterations" in encryption. An iteration is a single cycle in which a key and salt are mixed in such a way to make guessing the key harder. This is done many times so to make it computationally difficult for an attacker to reverse-guess the key, hence "iterations" (plural). Typically, a minimum required number of iterations is 1000, but it can be different than that. If you start with a really strong password, generally you need less.
IV (or "Initialization Vector") is typically a random value that's used for encryption of each message. Now, salt is used for producing a key based on a password. And IV is used when you already have a key and now are encrypting messages. The purpose of IV is to make the same messages appear differently when encrypted. Sometimes, IV also has a sequential component, so it's made of a random string plus a sequence that constantly increases. This makes "replay" attacks difficult, which is where attacker doesn't need to decrypt a message; but rather an encrypted message was "sniffed" (i.e. intercepted between the sender and receiver) and then replayed, hoping to repeat the action already performed. Though in reality, most high-level protocols already have a sequence in place, where each message has, as a part of it, an increasing packet number, so in most cases IV doesn't need it.
This example uses Golf framework. Install it first.
To run the examples here, create an application "enc" in a directory of its own (see mgrg for more on Golf's program manager):
mkdir enc_example cd enc_example gg -k encCopied!
To encrypt data use encrypt-data statement. The simplest form is to encrypt a null-terminated string. Create a file "encrypt.golf" and copy this:
begin-handler /encrypt public set-string str = "This contains a secret code, which is Open Sesame!" // Encrypt encrypt-data str to enc_str password "my_password" p-out enc_str @ // Decrypt decrypt-data enc_str password "my_password" to dec_str p-out dec_str @ end-handlerCopied!
You can see the basic usage of encrypt-data and decrypt-data. You supply data (original or encrypted), the password, and off you go. The data is encrypted and then decrypted, yielding the original.
Wednesday, December 25, 2024
Golf 136 released
- Any number expression can now use string subscription as a number, for instance:
set-string str='hello'
set-number num = 10+str[0]
A character is treated as an unsigned number ranging from 0-255 (i.e. unsigned byte).
Tuesday, December 24, 2024
Golf 132 released
- Individual bytes of a string (binary or text) can now be set using set-string by specifying the byte with a number expression within []. Since Golf is a memory-safe language, setting a byte this way is subject to a range check. For instance:
set-string str[10] = 'a'
- An individual byte of a string (binary or text) can now be obtained (as a number) with set-number using a number expression within []. Since Golf is a memory-safe language, getting a byte this way is subject to a range check. For instance:
set-number byte = str[10]
Sunday, December 15, 2024
Distributed computing made easy
Distributed computing is two or more servers communicating for a common purpose. Typically, some tasks are divvied up between a number of computers, and they all work together to accomplish it. Note that "separate servers" may mean physically separate computers. It may also mean virtual servers such as Virtual Private Servers (VPS) or containers, that may share the same physical hardware, though they appear as separate computers on the network.
There are many reasons why you might need this kind of setup. It may be that resources needed to complete the task aren't all on a single computer. For instance, your application may rely on multiple databases, each residing on a different computer. Or, you may need to distribute requests to your application because a single computer isn't enough to handle them all at the same time. In other cases, you are using remote services (like a REST API-based for instance), and those by nature reside somewhere else.
In any case, the computers comprising your distributed system may be on a local network, or they may be worldwide, or some combination of those. The throughput (how many bytes per second can be exchanged via network) and latency (how long it takes for a packet to travel via network) will obviously vary: for a local network you'd have a higher throughput and lower latency, and for Internet servers it will be the opposite. Plan accordingly based on the quality of service you'd expect.
Depending on your network(s) setup, different kinds of communication are called for. If two servers reside on a local network, then they would typically used the fastest possible means of communication. A local network typically means a secure network, because nobody else has access to it but you. So you would not need TSL/SSL or any other kind of secure protocol as that would just slow things down.
If two servers are on the Internet though, then you must use a secure protocol (like TSL/SSL or some other) because your communication may be spied on, or worse, affected by man-in-the-middle attacks.
Most of the time, your distributed system would be on a local network. Such network may be separate and private in a physical sense, or (more commonly) in a virtual sense, where some kind of a Private Cloud Network is established for you by the Cloud provider. It's likely that separation is enforced by specialized hardware (such as routers and firewalls) and secure protocols that keep networks belonging to different customers separate. This way, a "local" network can be established even if computers on it are a world apart, though typically they reside as a part of a larger local network.
Either way, as far as your application is concerned, you are looking at a local network. Thus, the example here will be for such a case, as it's most likely what you'll have. A local network means different parts of your application residing on different servers will use some efficient protocol based on TCP/IP. One such protocol is FastCGI, a high-performance binary protocol for communication between servers, clients, and in general programs of all kinds, and that's the one used by Golf. So in principle, the setup will look like this (there'll be more details later):
Next, in theory you should have two servers, however in this example both servers will be on the same localhost (i.e. "127.0.0.1"). This is just for simplicity; the code is exactly the same if you have two different servers on a local network - simply use another IP (such as "192.168.0.15" for instance) for your "remote" server instead of local "127.0.0.1". The two servers do not even necessarily need to be physically two different computers. You can start a Virtual Machine (VM) on your computer and host another virtual computer there. Popular free software like VirtualBox or KVM Hypervisor can help you do that.
In any case, in this example you will start two simple application servers; they will communicate with one another. The first one will be called "local" and the other one "remote" server. The local application server will make a request to the remote one.
On a local server, create a new directory for your local application server source code:
mkdir ~/local_server cd ~/local_serverCopied!
and then create a new file "status.golf" with the following:
begin-handler /status public silent-header get-param server get-param days pf-out "/server/remote-status/days=%s", days to payload pf-out "%s:3800", server to srv_location new-remote srv location srv_location \ method "GET" url-path payload \ timeout 30 call-remote srv read-remote srv data dt @Output is: [<<p-out dt>>] end-handlerCopied!
The code here is very simple. new-remote will create a new connection to a remote server
Thursday, December 12, 2024
How is memory organized in Golf
- Length (in bytes) of the string,
- "Ref count" (Reference count), stating how many Golf variables point to string,
- Status is used to describe string, such as whether it's scope is process-wide, if it's a string literal etc,
- "Next free" points to the next available string block (if this one was freed too),
- "Data ptr" points back to the string, which is used to speed up access.
Each memory block (ID+string+trailing null) is a memory allocated by standard C'd memory allocation, while memory table is a continuous block that's frequently cached to produce fast access to string's properties.