Meow Programming Language v0.21.1: A Top-Level Function Named Rather Than Called

Released 2026-08-20. v0.21.0 made a member readable as a value. A plain top-level function was still not one, and saying so leaked Go’s own complaint:

meow greet(who string) string { bring "hi " + who }
nya(greet)
cannot use greet (value of type func(who string) string) as meowrt.Value value
in argument to meow.Nya: func(who string) string does not implement meowrt.Value

Not a Hiss!, and not something a Meow program could act on. It was not only nya — no top-level function could be used as a value at all, so the plainest functional idiom did not work:

meow double(n int) int { bring n * 2 }
nya(lick([1, 2], double))                       # the same Go error
nya(lick([1, 2], paw(n) { bring double(n) }))   # what you had to write instead

A function named rather than called is the function

meow double(n int) int {
  bring n * 2
}

meow join(a string, b string) string {
  bring a + "-" + b
}

nyan f = double
nya(f(21))                    # 42
nya(3 |=| double)             # 6
nya(lick([1, 2, 3], double))  # [2, 4, 6]
nya(double)                   # <meow double>

nyan greet = join("hi")       # already worked: a partial call
nya(greet("nyan"))            # hi-nyan

A top-level function is a plain Go function, which nothing taking a Meow value can be handed, so it is wrapped into the value it has to be — the same wrapper a call with too few arguments already makes, with none of them supplied. Arity and currying therefore come out of the existing path rather than a new one.

Shadowing

A name a local has taken over is still the local’s. What says so is the type recorded for that very occurrence, resolved by the checker in the scope it was written in:

meow greet(who string) string { bring "hi " + who }

meow a() string { nyan greet = "shadowed"   bring greet }   # shadowed
meow b() litter { nyan greet = [1, 2]       bring greet }   # [1, 2]

nya(greet("nyan"))            # hi nyan   — still the top-level one
nyan g = greet
nya(g("again"))               # hi again

A nested meow is already held as a value and needs no wrapping.

The playground’s interpreter had always answered this correctly — only the compiled path could not — so this release is where the two backends agree again, with a test pinning the agreement.

Upgrading

Purely additive: programs that wrapped a function in a paw to hand it to lick or a pipe still work, and can now drop the wrapper.

brew upgrade meow
# or
go install github.com/135yshr/meow/cmd/meow@v0.21.1

One thing this release did not fix, found on the way: calling through a name a local has taken over still went to the top-level function. That is v0.21.2.