google / starlark-go

Starlark in Go: the Starlark configuration language, implemented in Go
BSD 3-Clause "New" or "Revised" License
2.26k stars 204 forks source link

`dir()` for current environment? #479

Open SportyWifey opened 1 year ago

SportyWifey commented 1 year ago

In Python, dir() without args can list all available funcs and vars in current environment, like this:

❯ python
Python 3.11.3 (main, May  3 2023, 23:19:07) [Clang 14.0.3 (clang-1403.0.22.14.1)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> dir()
['__annotations__', '__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__']
>>>

So how I can do this with Starlark?

adonovan commented 1 year ago

Currently, you can't. There is an open proposal at bazelbuild/starlark#218 to support a predeclared builtins dict variable, which (in conjunction with getattr) would make it easier to write code that works before and after the addition of a new builtin. But there are no plans to add a Python-style dir.

What problem are you trying to solve?

SportyWifey commented 1 year ago

@adonovan For the scenarios that ships with REPL mode as playground for newcomer. e.g. use Starlark as script language but also with preset variables and functions, so a robust REPL with helper methods like dir() would be great for developers to play with and explore.

adonovan commented 1 year ago

For the scenarios that ships with REPL mode as playground for newcomer. e.g. use Starlark as script language but also with preset variables and functions, so a robust REPL with helper methods like dir() would be great for developers to play with and explore.

It's easy enough to implement, though it's much harder to specify, and the behavior it exhibits in CPython requires a particular implementation strategy to represent the environment (happily, the same one used by the Go and Java implementations, but that's just luck). The question is: what exactly counts as in scope?

For example, in Python, this call to dir returns ['y'], but if you add the statement print(x) within g, it returns ['x', 'y'] because it really reports the set of locals and free variables that are accessible to the representation of the inner function, not the set of all local names that are in scope:

   def f(x):
     def g(y):
      dir()

It seems like more of an expedient feature of a REPL than a serious feature one would ever use in a program. In any case, proposals to change the language should go through bazelbuild/starlark.

SportyWifey commented 1 year ago

@adonovan easy enough to implement? So will you add it? It's okay to access it on the first level only, and ignore nested defs

adonovan commented 1 year ago

easy enough to implement? So will you add it?

I think you missed the point of the paragraph in which I used those words. We don't add features until we've agreed on their specification, and the specification for this function is not trivial.