Originally created by @philippemerle on GitHub (Mar 4, 2024).
The language reference says that a module amending another module inherits from all the members of the amended module. But functions of the amended module seem to be not inherited from as shown in the following example.
File base_template.pkl
persons: Listing<Person>
class Person {
name: String
}
function buildPerson(val: String): Person = new {
name = val
}
File my_template.pkl
amends "base_template.pkl"
persons {
new Person { name = "Me"}
buildPerson("you")
}
Evaluating my_template.pkl produces the following error
–– Pkl Error ––
Cannot find method `buildPerson`.
5 | buildPerson("you")
^^^^^^^^^^^^^^^^^^
at my_template#persons[#2] (file:///.../my_template.pkl, line 5)
3 | persons {
^^^^^^^^^
at my_template#persons (file:///.../my_template.pkl, line 3)
106 | text = renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
at pkl.base#Module.output.text (https://github.com/apple/pkl/blob/0.25.2/stdlib/base.pkl#L106)
Do I miss something?
Originally created by @philippemerle on GitHub (Mar 4, 2024).
The language reference says that a module amending another module inherits from all the members of the amended module. But functions of the amended module seem to be not inherited from as shown in the following example.
File `base_template.pkl`
```
persons: Listing<Person>
class Person {
name: String
}
function buildPerson(val: String): Person = new {
name = val
}
```
File `my_template.pkl`
```
amends "base_template.pkl"
persons {
new Person { name = "Me"}
buildPerson("you")
}
```
Evaluating `my_template.pkl` produces the following error
```
–– Pkl Error ––
Cannot find method `buildPerson`.
5 | buildPerson("you")
^^^^^^^^^^^^^^^^^^
at my_template#persons[#2] (file:///.../my_template.pkl, line 5)
3 | persons {
^^^^^^^^^
at my_template#persons (file:///.../my_template.pkl, line 3)
106 | text = renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
at pkl.base#Module.output.text (https://github.com/apple/pkl/blob/0.25.2/stdlib/base.pkl#L106)
```
Do I miss something?
Scoping rules in Pkl can be a bit tricky. You can use module to reference top level variables and functions:
amends "base_template.pkl"
persons {
new Person { name = "Me"}
module.buildPerson("you")
}
Also: if you use our IntelliJ plugin you should see an error telling you this function is not found.
@stackoverflow commented on GitHub (Mar 4, 2024):
Scoping rules in Pkl can be a bit tricky. You can use `module` to reference top level variables and functions:
```
amends "base_template.pkl"
persons {
new Person { name = "Me"}
module.buildPerson("you")
}
```
Also: if you use our IntelliJ plugin you should see an error telling you this function is not found.
Thank you the provided solution. But this will be simpler if inherited functions could be called directly without prefixing them by module.. Perhaps in a future pkl release?
@philippemerle commented on GitHub (Mar 4, 2024):
Thank you the provided solution. But this will be simpler if inherited functions could be called directly without prefixing them by `module.`. Perhaps in a future pkl release?
The scoping rules in place here provide an important safety net; that the resolved member can't change by adding something else in the (grand)parent module.
Without this rule, it would be possible to change what a variable/method resolved to by changing something in the base module. It would make it so that adding names to a module might produce very unexpected results in the generated configuration.
function foo() = "bar"
class MyObject {
prop: String
+
+ function foo() = "baz"
}
obj: MyObject
This change seems innocent when just looking at parent.pkl, but it would change foo() within child.pkl to resolve to a different method. This behavior would make it too easy for pkl code to break in hidden ways.
The same resolution rules apply to properties, too.
@bioball commented on GitHub (Mar 4, 2024):
The scoping rules in place here provide an important safety net; that the resolved member can't change by adding something else in the (grand)parent module.
Without this rule, it would be possible to change what a variable/method resolved to by changing something in the base module. It would make it so that adding names to a module might produce very unexpected results in the generated configuration.
For example, if this worked:
parent.pkl
```groovy
function foo() = "bar"
class MyObject {
prop: String
}
obj: MyObject
```
child.pkl
```groovy
obj {
prop = foo()
}
```
Then, a new `function foo()` was introduced:
```diff
function foo() = "bar"
class MyObject {
prop: String
+
+ function foo() = "baz"
}
obj: MyObject
```
This change seems innocent when just looking at `parent.pkl`, but it would change `foo()` within `child.pkl` to resolve to a _different_ method. This behavior would make it too easy for pkl code to break in hidden ways.
The same resolution rules apply to properties, too.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Originally created by @philippemerle on GitHub (Mar 4, 2024).
The language reference says that a module amending another module inherits from all the members of the amended module. But functions of the amended module seem to be not inherited from as shown in the following example.
File
base_template.pklFile
my_template.pklEvaluating
my_template.pklproduces the following errorDo I miss something?
@stackoverflow commented on GitHub (Mar 4, 2024):
Scoping rules in Pkl can be a bit tricky. You can use
moduleto reference top level variables and functions:Also: if you use our IntelliJ plugin you should see an error telling you this function is not found.
@philippemerle commented on GitHub (Mar 4, 2024):
Thank you the provided solution. But this will be simpler if inherited functions could be called directly without prefixing them by
module.. Perhaps in a future pkl release?@bioball commented on GitHub (Mar 4, 2024):
The scoping rules in place here provide an important safety net; that the resolved member can't change by adding something else in the (grand)parent module.
Without this rule, it would be possible to change what a variable/method resolved to by changing something in the base module. It would make it so that adding names to a module might produce very unexpected results in the generated configuration.
For example, if this worked:
parent.pkl
child.pkl
Then, a new
function foo()was introduced:This change seems innocent when just looking at
parent.pkl, but it would changefoo()withinchild.pklto resolve to a different method. This behavior would make it too easy for pkl code to break in hidden ways.The same resolution rules apply to properties, too.
@bioball commented on GitHub (Mar 4, 2024):
Closing as not planned, as this works as-intended.