Add "with ... do" statement for context management#4367
Conversation
|
Can we do R = QQ[x,y,z]
x = a
f = with R do (
x^3 + y^3 + z^3
); |
|
Yeah we should be able to by defining the right enter and exit methods for |
|
I don't think stuffing it in the ring object is good, for parallel reasons. Unless we can give it a unique key, that the enter method and exit method can use. |
|
I remembered that we have PolynomialRing.EnterMethod = R -> (
scan(R.generatorSymbols, sym -> pushvar(sym, value sym));
use R)
PolynomialRing.ExitMethod = R -> scan(R.generatorSymbols, popvar)Then this gives: i1 : R = QQ[x,y,z];
i2 : x = a
o2 = a
o2 : Symbol
i3 : with R do x^3 + y^3 + z^3
3 3 3
o3 = x + y + z
o3 : R
i4 : x
o4 = a
o4 : Symbol |
|
Edit: Well, they're thread-safe, but I hope I didn't break the behavior. We have a different copy of the stack in each thread. What if we push in the parent thread and want to pop in another thread? Is that something we might want to do? Edit 2: Never mind -- I guess they're still not thread-safe. Getting some weird behavior. I'll remove that commit |
|
I prefer this syntax for mutex management. e.g. |
|
I went ahead and added documentation and tests, and also added the short-term fix for #3239 using the new proposed syntax. In addition to the cases mentioned above, I also added i1 : with RR_100 do numeric pi
o1 = 3.141592653589793238462643383279
o1 : RR (of precision 100)I also add |
3a5f322 to
516131f
Compare
|
Hmm, adding this syntax slows down the interpreter (by ~35% according to Claude). Going back to draft while I investigate |
|
After some analysis of the code by Claude, I think I have a simple fix. The moral of the story is apparently not to add more local variables to |
|
Can you say more? Would we get a speed up by removing some local variables from evalraw? What about other functions that run frequently? Would be good to pick a representative example as baseline for interpreter benchmarks. |
|
That seemed to fix it -- the builds are taking the usual amount of time again! Currently, the way that scc1 generates the c files, it lists every local variable at the top of a function, regardless of whether they're in some specific I had Claude move all the various cases in |
|
... so moving all the |
|
I don't think you can rely on GitHub builds for accurate benchmarks, there's quite a bit of variation based on time of day. |
|
After discussing this with Mike, I've updated the implementation a bit. The return value of the entrance method is passed Edit: Simplified this a bit further, so the exit method only takes one argument, the return value of the enter method. |
|
I have to say I find the combination of the same syntax for mutexes, rings, fields, and files potentially very confusing. |
That's a fair point, but is it substantially different from overloading methods on different types? Something else I'm considering adding to this PR: lock Function := f -> (
mutex := new Mutex;
x -> with mutex do f x)Then users could write thread-safe functions without having to deal with mutexes directly, and the Edit: Done |
|
This is what I was suggesting for an interpreter keyword with the mutex stored in the closure. |
Right -- I just wasn't sure how we could implement something like this specifically for function closures. Keywords just act on Looking back, I suppose we could have a compiled function that takes a function closure (or any function object, for that matter), and constructs a compiled function closure with a mutex in it. That might work, I think, but it's a lot less general than this proposal. |
|
Converting to a draft -- after I made the above comment, I decided to go ahead and code it up. See #4378. Both PR's provide a |
We add support for 4 types: * File (close on exit) * Mutex (lock on entrance, unlock on exit) * EngineRing (use on entrance, restore previous symbol values on exit) * InexactField (sets and restores defaultPrecision)
Also bump Python package to version 1.1
After writing #4350 (comment), I got excited about this idea and figured I'd throw it together.
We introduce a new type of statement in Macaulay2,
with x do yfor context management, similar to Python. We can install entrance and exit methods for the type ofx, and the exit methods are guaranteed to run even ifyraises an error.By default, if
xis a file, then we close it on exit. If it's a mutex, then we lock on entrance and unlock on exit.Silly example:
Draft for now for comments. I also haven't written any documentation or tests yet.
AI Disclosure
Some brainstorming with Claude Chat, but the code is all mine.