Refer to functions through their identifiers #183

Closed
opened 2025-12-30 01:21:49 +01:00 by adam · 2 comments
Owner

Originally created by @hmonfleur on GitHub (Jul 10, 2024).

I want to refer to functions through their identifiers.
Declaring a function and a class:

function foo():Int = 1

class A{
  hidden f: () -> Int
  x = f.apply()
}

Instantiating the following object:

a = new A{
  f = foo
}

produces:
Cannot find property `foo`.

Being unsure of how to refer to "foo" I also tried:

a = new A{
  f = module.foo
}

Which produces:
Cannot find property `foo` in module `text`.

However the following code:

hidden foo = () -> 1

class A{
  hidden f: () -> Int
  x = f.apply()
}

a = new A{
  f = foo       // same behavior with module.foo
}

produces:

{
  "a": {
    "x": 1
  }
}

Am I missing something or is it the expected behavior ?

Originally created by @hmonfleur on GitHub (Jul 10, 2024). I want to refer to functions through their identifiers. Declaring a function and a class: ```pkl function foo():Int = 1 class A{ hidden f: () -> Int x = f.apply() } ``` Instantiating the following object: ```pkl a = new A{ f = foo } ``` [produces](https://pkl-playground.vercel.app/?share=unless-enough-deeply): ```Cannot find property `foo`.``` Being unsure of how to refer to "foo" I also tried: ```pkl a = new A{ f = module.foo } ``` Which [produces](https://pkl-playground.vercel.app/?share=forget-saddle-laugh): ```Cannot find property `foo` in module `text`.``` However the following code: ```pkl hidden foo = () -> 1 class A{ hidden f: () -> Int x = f.apply() } a = new A{ f = foo // same behavior with module.foo } ``` [produces](https://pkl-playground.vercel.app/?share=truck-species-screen): ```pkl { "a": { "x": 1 } } ``` Am I missing something or is it the expected behavior ?
adam closed this issue 2025-12-30 01:21:49 +01:00
Author
Owner

@holzensp commented on GitHub (Jul 12, 2024):

Unfortunately, this is more complicated than you'd hope. Functions and properties have entirely different namespaces in Pkl. This means that you can have a function foo() and a property foo side-by-side without issue, but it also means that, notationally, functions are not as first-class as you'd like (believe me, I've wanted this too). If you want to pass a function as a function-typed-value, you have to wrap it in a lambda;

function foo():Int = 1

class A {
  hidden f: () -> Int
  x = f.apply()
}

a: A = new { // <- side-note; prefer type signatures, because `new A {` doesn't imply at all that `a: A`.
  f = () -> foo() // <- this works
}

Here's a thing to consider (and I'm mindful you probably reduced the real example to get here); whenever you write a zero-argument function in Pkl, alarm bells should be ringing. You never need those; since there are no side-effects, there's no reason to postpone evaluation "manually," and since Pkl is late-bound, all properties essentially are zero-arity functions.

@holzensp commented on GitHub (Jul 12, 2024): Unfortunately, this is more complicated than you'd hope. Functions and properties have _entirely different namespaces_ in Pkl. This means that you can have a function `foo()` and a property `foo` side-by-side without issue, but it also means that, notationally, functions are not as first-class as you'd like (believe me, I've wanted this too). If you want to pass a `function` as a function-typed-value, you have to wrap it in a lambda; ```pkl function foo():Int = 1 class A { hidden f: () -> Int x = f.apply() } a: A = new { // <- side-note; prefer type signatures, because `new A {` doesn't imply at all that `a: A`. f = () -> foo() // <- this works } ``` Here's a thing to consider (and I'm mindful you probably reduced the real example to get here); whenever you write a zero-argument function in Pkl, alarm bells should be ringing. You never need those; since there are no side-effects, there's no reason to postpone evaluation "manually," and since Pkl is late-bound, all properties _essentially are zero-arity functions_.
Author
Owner

@bioball commented on GitHub (Jul 22, 2024):

Closing this; if you need to refer to a function as a value, use a lambda notation like @holzensp mentioned. Methods (those that start with a function keyword) can't be passed as a value.

@bioball commented on GitHub (Jul 22, 2024): Closing this; if you need to refer to a function as a value, use a lambda notation like @holzensp mentioned. Methods (those that start with a `function` keyword) can't be passed as a value.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/pkl#183