sci

2026-02-21T10:14:58.976649Z

As far as I know there isn't, but just in case I missed something, is there a way in Sci to control what methods can be invoked on objects and what not? I'm looking for something more granular than {:classes {'java.io.Reader java.io.Reader}}, maybe something like {:classes {'java.io.Reader {'close http://java.io.Reader/close}}}` . Ideally, I would be able to provide an implementation per method like what we can do with functions.

2026-02-21T10:17:19.024049Z

With functions I can build a decent sandbox (e.g. no IO to certain resources), but the moment I allow certain classes, let say java.io.Reader I give access to my whole filesystem

borkdude 2026-02-21T10:18:30.023719Z

is this for a binary or JVM usage?

2026-02-21T10:18:40.475629Z

JVM usage

borkdude 2026-02-21T10:19:08.956469Z

ok, we can accomplish this for sure but it needs some work. with static methods it's already possible

borkdude 2026-02-21T10:19:20.905839Z

in binaries you can control the access via the reflection config

2026-02-21T10:19:50.356809Z

Ah cool. Is it something I could work on or is it quite involved?

2026-02-21T10:20:20.973299Z

for the JVM I mean

borkdude 2026-02-21T10:20:38.519909Z

the main thing would be to prevent performance loss for the paths that don't use this.

borkdude 2026-02-21T10:20:55.586279Z

you can see how I implemented it for static methods in babashka impl/classes.clj + SCI

2026-02-21T10:21:13.128139Z

Ok thanks I will have a look

2026-02-21T10:45:18.670789Z

It seems at the moment you can override static methods, but you can't block them individually. E.g. the following adds a new static method, but this doesn't block the other ones:

(sci/eval-string "(Class/forName \"java.lang.String\")"
                 {:imports {'Class 'java.lang.Class}
                  :classes {'java.lang.Class {:class Class :static-methods {'SomethingElse (fn [& _] :dude)}}}}) ;=> java.lang.String
I will have a look at the implementation now

borkdude 2026-02-21T10:49:47.633859Z

true

borkdude 2026-02-21T10:50:00.651949Z

but probably related since in SCI we search if there is an override

borkdude 2026-02-21T10:50:11.313869Z

and at that spot you could also say: we won't execute this

2026-02-21T10:53:07.163139Z

Yeah probably it could be mixed with something here https://github.com/babashka/sci/blob/b0d06162a4a03abee2045075833508b0f5b6b095/src/sci/impl/analyzer.cljc#L1043-L1050 I can imagine that doesn't have to add any additional performance loss

2026-02-21T10:55:39.974979Z

Maybe naive observation, but the function is called analyze-dot , but there is no . in static calls. I guess I shouldn't take this too literal and it refers just to interop in general

borkdude 2026-02-21T11:03:28.210679Z

(. Thread sleep 1000)

2026-02-21T11:03:51.696469Z

Ah of course 😅

2026-02-21T11:28:50.130429Z

I'm guessing to add control over instance methods we would have to add a conditional branch as with the :static-methods in the analyzer https://github.com/babashka/sci/blob/407aa71dd0e6e20de68494b4b0d365d7df2a3fd1/src/sci/impl/analyzer.cljc#L998-L1002 . So if we do it like that, for all paths that don't use this there would be an overhead of a failing test:

(if-let [f (some-> ctx :env deref :class->opts :instance-methods (get (interop/fully-qualify-class ctx instance-expr))
                                                (get method-expr)) 
  
  )
Is that potentially acceptable or likely to cause too much loss in performance?

2026-02-21T11:31:30.878639Z

Maybe this is even simplified because there could be several matching classes actually

2026-02-21T11:37:47.856389Z

A tiny optimization could be changing the whole some-> to (-> ctx :env deref (some-> :class->opts :instance-methods ...)) as the first bit will always be there I think so no need to add the overhead of tests

borkdude 2026-02-21T11:52:57.225119Z

is that change inside of the node?

2026-02-21T11:57:21.770999Z

Not sure what you mean by that. I was thinking that we would have to add a similar test as with the :static-methods. So something like this if-let block https://github.com/babashka/sci/blob/407aa71dd0e6e20de68494b4b0d365d7df2a3fd1/src/sci/impl/analyzer.cljc#L1032-L1040 For the instance-methods we maybe also have to walk a class hierarchy, so maybe a more involved test. Maybe this could be cached as with protocols

borkdude 2026-02-21T12:02:22.503169Z

what I mean is: would your check be inside sci.impl.types/->Node or outside. outside is better but we probably don't know the target class

2026-02-21T12:03:38.427239Z

I don't know yet. I thought it could be outside, but maybe it is time for some experimentation and see how far I can get

2026-02-21T16:59:17.258149Z

I've created a first implementation in this https://github.com/babashka/sci/pull/1027 . It is passing basic tests, but I will test it on my project as well to see if it is sufficient in practise.