-
Notifications
You must be signed in to change notification settings - Fork 237
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support redefinable def
and defmacro
bindings using :redef
#898
Conversation
The following is what is meant by "expand function", right? Line 2272 in cddc2a8
|
@sogaiu Yes, thanks for the clarification. A function passed with that key to |
Not sure I understand why this is different to a var? |
IIUC, it's related to this idea:
via: http://thegeez.net/2021/10/28/janet_web_app_aws_lambda.html |
@andrewchambers Assuming that #897 is merged and the source map data associated with However, the key point is that you don't need to change all your bindings to make REPL-driven development more practical (and then change them all back again when you're finished; being careful not to change the |
I wonder if it could just be an option that gets passed to the compiler on a global level. |
That sounds much simpler and less subtle to me 👍 . |
@andrewchambers How about a dynamic binding (e.g. @bakpakin Do you have any thoughts? |
That's the sort of thing I was talking about, but I don't really know what is the best way as I haven't needed such a feature so far. |
def
and defmacro
bindings using :redef
def
and defmacro
bindings using :dynamic
Update: Following the discussion below, I've gone back to using I've changed the implementation slightly and now track whether a Together with this change, I've added global support for dynamic You can see examples of how to use the functionality in the updated test suite and I've also updated the OP to reflect the changes to make it easier for those coming to this PR in the future. |
Tried it out briefly:
Looks good so far :) @saikyun May be this is of interest to you too? |
Isn't it a bit confusing to call it How about something like |
@saikyun Good point! |
@saikyun If we went with something else, I'd suggest going back to |
For me it's important to be able to redefine things across files / modules. I've managed to do this earlier by never replacing I couldn't get this scenario to work using Example 1Code
Execution
Example 2Code
Execution
|
@saikyun You're right that, by itself, this PR won't allow you to update the bindings created via (spit "lul.janet" `(def a 10) (print "1st a is: " a)`)
(use ./lul)
(defn b [] (+ a a))
(print "call 1: " (b))
(spit "lul.janet" `(def a 1337) (print "2nd a is: " a)`)
(dofile "lul.janet" :env (curenv))
(print "call 2: " (b)) Using The result: $ ./build/janet -D saikyun.janet
1st a is: 10
call 1: 20
2nd a is: 1337
call 2: 2674 I use the new command line argument and so don't need to manually add |
@saikyun Got it working with your first example: $ ./build/janet -D -e "(put module/loaders :source (fn source-loader [path args] (put module/loading path true) (defer (put module/loading path nil) (def env (get module/cache path)) (dofile path :env env ;args))))" saikyun.janet
1st a is: 10
call 1: 20
2nd a is: 1337
call 2: 2674 The new module loader is almost the same as the one in (def env (get module/cache path))
(dofile path :env env ;args) |
That's nice! However, now we have a new problem, that you can run code using old symbols after having removed them: Code
Executing
|
Some notes:
|
Is it meant to work with
|
I might be off here, but for the Here's a bit from pyrmont (see #897) about the situation:
May be pyrmont can confirm / clarify / deny :) |
def
and defmacro
bindings using :dynamic
def
and defmacro
bindings using :redef
@saikyun Thanks for really stress testing this. In response:
|
Just getting back from vacation, this looks pretty good to me. Glad we have gone to a global dynamic setting rather than a per binding indication, since that is the main point - a global setting that will allow interactive development with no change to code. However, wondering if the existing |
@bakpakin Hope you had a good break :D My responses:
|
Some tooling I use talks to janet via its repl (not netrepl). I'd like the option of only having the redefining behavior without debugging being enabled (though I imagine occasionally I'd want both). IIUC keeping things separate seems to be a straight-forward way to achieve this. Please indicate if this understanding seems off. |
If debug-mode affects performance, I'd like them to be separate (though
maybe `-d` should always enable `-D` as well?). I plan on having `-D`
always on in Freja, so that one can change internal functions. But I don't
necessarily want debug-mode to always be on.
It would also be OK if I can use neither `-d` nor `-D` but instead enable redef by using the `(setdyn :redefs true)`.
|
IIUC, currently Line 3373 in 199ec36
I don't think that's something I want to happen most of the time, though I envision using the redef behavior while developing. Not sure what else is affected. To get the effect of both at the same time, I think it makes more sense to:
rather than changing |
@bakpakin It looks like Was this intentional? |
@elimisteve There is no Lines 3576 to 3639 in 07ec892
|
@bakpakin Re: 99cfbaa#diff-e120880268b4f0f04177470180f50ee0d2c7ac13cb83bb778b6d81efda1cbbccR3661 , what if people want to make Janet's behavior more dynamic/redefinable without enabling debug mode? |
@elimisteve I do this ATM: So in a way |
I can't thumbs up the merge so 🥳🥳🥳🥳🥳🥳🥳 |
@elimisteve and others - I found that the To reproduce:
|
@sogaiu Does having debugging enabled seem to mess anything up or slow anything down when wanting to make Janet more dynamic/"redefinable" rather than actually debug? (Thanks!) |
@elimisteve One difference I'm aware of is what happens when there is an error, e.g.:
That is, the interactive debugger is invoked. |
Tried another thing. The following doesn't give an error:
|
With pyrmont's #910 applied, I no longer see the reported behavior mentioned in #898 (comment) |
@sogaiu Great! So |
You left a couple comments about different behavior so I'm just making sure 😉 |
@elimisteve I'm not aware of any other issues ATM :) |
This PR adds support for using the metadata keyword
:redef
withdef
anddefmacro
bindings. A binding that has this metadata can be be redefined and existing references to that binding will use the redefined value. This is useful for interactive environments in which a dynamic environment is important (e.g. a REPL). All top-leveldef
anddefmacro
bindings can be made redefinable by settings the:redefs
dynamic binding totrue
(as done by the new command line option-D
).Background
Janet supports three types of bindings:
var
bindings,def
bindings anddefmacro
bindings.var
bindings store the evaluated result in an array associated with the:ref
keyword in the binding table. Bothdef
anddefmacro
bindings store the evaluated result as a value associated with the:value
keyword.When
var
bindings are referenced from other contexts, the Janet compiler stores a reference to the:ref
array and retrieves the value from the array at runtime. In contrast, whendef
anddefmacro
bindings are referenced from other contexts, the Janet compiler inserts a direct reference to the value. In most situations, this is appropriate.def
anddefmacro
bindings are not intended to be mutable; indeed, that is the reason Janet hasvar
bindings.The exception is in interactive environments (e.g. a REPL). In these environments, if a user redefines a
def
ordefmacro
binding because they are iteratively developing a program, they most likely want all references to that binding to use the updated value.Implementation
This PR creates a new member in the
JanetBinding
struct,.dynamic
, the value for which can either beJANET_BINDING_STATIC
orJANET_BINDING_DYNAMIC
. When.dynamic
is set toJANET_BINDING_DYNAMIC
,def
anddefmacro
bindings function likevar
bindings (although they cannot be changed usingset
).A user can specify that a
def
ordefmacro
binding is redefinable using the:redef
metadata value. Alternatively, the user can make almost all1def
anddefmacro
bindings redefinable by setting the:redefs
dynamic binding totrue
. A user can force alldef
anddefmacro
bindings in a Janet REPL to be redefinable by using the command line option-D
.Footnotes
A user can ensure that a
def
ordefmacro
binding is never made redefinable by setting the:redef
metadata value tofalse
. ↩