<enebo[m]1>
headius: kares Something to consider in that PR is whether I killed a deprecated method which someone may expect. None of those deprecations are remotely new and I did not remove very many
<enebo[m]1>
We have sooo many deprecated methods but I am a bit shy on being more aggressive due to native extension concerns
<enebo[m]1>
So subbu|away wrote a comment like a decade ago which has been bugging me to the point I started to do some block cleanup...SSS FIXME: How is it even possible to "call" a NORMAL block?
<headius[m]>
yeah deprecations are tough without having more integration testing across key exts
<headius[m]>
I don't think it is possible to call a normal block
<headius[m]>
it will always be reified into a proc or lambda if it is callable as a Proc
<headius[m]>
or turned into a method in define_method
<enebo[m]1>
It is not yet in spec:ruby:fast I found several which make it through call()
<headius[m]>
I would like to get stack traces for that because I don't think it should be possible
<enebo[m]1>
well so the thing is I have also seen the interesting revert you put in for lambdas doing each_with_index
<enebo[m]1>
I feel like we somehow have some stuff twisting around somewhere
<enebo[m]1>
but I am looking at figuring out a couple of these mysteries and hopefully things will be simpler
<enebo[m]1>
The other thing I am looking at is **kw to a method with no args which is currently broken
<enebo[m]1>
which is not even a block issue per se but block pre-processing may complicate this in block case
<enebo[m]1>
So I am guessing block.type is actually intended to demarcate Lambda vs not lambda here
<enebo[m]1>
but since it likely is chunk { |mine| } it will show up as NORMAL
<headius[m]>
ahh yeah it should probably be reified as a lambda or proc before being stored
<headius[m]>
logically it would have to have been reified to be stored from Ruby, but we have the raw block in Java so we just store that
<enebo[m]1>
ok well so far this has been productive...one use was somenoe picking call because yield is IRubyObject and not IRubyObject[]
<enebo[m]1>
yieldValues passes so that one maybe is ok using that instead of call
<headius[m]>
yeah should be fine
<enebo[m]1>
The other was implicitly making a proc internally but retaining the type as normal
<headius[m]>
main diff in call and yield is that magic first argument stuff is differenty I think
<enebo[m]1>
"yeah should be fine" we shall see but yeah if it ends up not being fine we will just figure out what the difference is
<enebo[m]1>
yeah
<enebo[m]1>
I am trying to get that one method down to something which is not dual path which should make us abe to bifurcate an IRHelper method into two
<enebo[m]1>
One huge issue MRI has and we inherit for a long period of time is they ball up all their logic into multistate tangles of state
<headius[m]>
that
<headius[m]>
that's for sure
<enebo[m]1>
We do this raw pass through of block.type in all Java invokers and a few other places
<enebo[m]1>
I feel this should only be LAMBDA or PROC
<headius[m]>
yeah probably
<enebo[m]1>
Interesting too we are not making LAMBDA as a forced convention for JI
<headius[m]>
oh for blocks used as JI impls?
<enebo[m]1>
If we are writing a closure to represent last argument I feel we know we have the right arity
<headius[m]>
yeah that is an interesting observation
<headius[m]>
probably should be lambda based on the semantics of Java methods
<headius[m]>
and even Java lambdas
<headius[m]>
e.g. return is always local
<enebo[m]1>
oh well actually I am just seeing block being setup as an arg for *MethodInvoker
<headius[m]>
yeah but that is basically the same as Interface.impl { }
<headius[m]>
so it is using a block body as an impl of a Java method, maybe it should be forced to behave like a Ruby lambda?
<headius[m]>
I do not know the answer because maybe you are doing something weird and want the non-local return or soft arity
<enebo[m]1>
The supplier of values is Java right?
<enebo[m]1>
I mean shouldn't we know it will send a particular number of arguments
<enebo[m]1>
I guess if we say those will behave as lambdas we will not push nils and crap
<enebo[m]1>
or if Java passes a single argument and it happens to be a RubyArray it won't spread?
<headius[m]>
yeah java and we just pass through whataver the interface signature is
<headius[m]>
Java passing RubyArray 🤣
<headius[m]>
I don't want to think about that
<enebo[m]1>
HAHA yeah so interface with List will get RubyArray and if our block is n args it will spread
<headius[m]>
I think we did do something to java.util.List to allow it to be coerced to array in masgn though so even that might be possible
<headius[m]>
yeah
<enebo[m]1>
amd I see we have lambda code doing spreads
<headius[m]>
so if we set to lambda semantics we would not be at risk of accidentally spreading a list argument
<headius[m]>
oh so it would not change that behavior?
<enebo[m]1>
Actually maybe lambda never does that
<enebo[m]1>
but I would be more concerned that people are depending on proc behavior now that I think about it
<enebo[m]1>
but only in the same of 1-artity Java interface method and block having n params
<enebo[m]1>
Interesting that we can actually determine that :)
<enebo[m]1>
I have another thought though
<enebo[m]1>
Block.Type.JAVA
<headius[m]>
interesting
<enebo[m]1>
the advantage of a new type would be no arity checking but allow spreading
<enebo[m]1>
we know we will never get nothing in this case
<headius[m]>
hmm yeah I guess another consideration here is if you want lambda semantics there's no way to do it in an inline block
<enebo[m]1>
we may have to nil pad unused params because Java never sent them
<headius[m]>
you'd have to do &lambda{...}
<enebo[m]1>
yeah that's true
<enebo[m]1>
I could see someone potentially wanting it both days
<enebo[m]1>
err ways
<enebo[m]1>
Now that I am thinking about this I think I would prefer lambda by default
<enebo[m]1>
but I think we cannot just change this because for sure someone is relying on proc behavior somehow
<headius[m]>
probably 😀
<headius[m]>
enebo: there's a bug here because it does not provide an encoding for the strings:
<headius[m]>
but I do not remember which encoding to get for external encoding of an IO
<enebo[m]1>
did someone report against this or did you notice it?
<headius[m]>
hmm actually I am not sure what is right behavior
<headius[m]>
I am trying to get psych tests green (they never have been)
<headius[m]>
some of the failures are due to us passing strings through here as ASCII-8BIT
<headius[m]>
if the underlying IO encoding is not compatible it errors
<enebo[m]1>
oh well I would almost think IO instance already has logic for what it should be
<enebo[m]1>
but you need to also transcode too right?
<headius[m]>
well now I am wondering
<headius[m]>
this is for OutputStream which just has byte[]
<headius[m]>
so we don't know what encoding to use for it
<enebo[m]1>
Originally with just seeing the code I half wondered if it was just bytes and should be binary
<headius[m]>
this is basically how IOOutputStream short-circuits the dyncall to write
<enebo[m]1>
Seems like we know the destined encoding though at the time we make the stream instance from IO itself
<headius[m]>
maybe it should just call the normal write directly rather than using this interface which obscures encoding
<enebo[m]1>
but using write would definitely make it behave like write was doing it...is that what it should do though since write will do console/int/ext + transcoding
<headius[m]>
the change just does the same string construction for the fast path as for the slow path, and calls RubyIO.write directly rather than indirecting through that OutputStream impl
<headius[m]>
bit more code cleanup in that commit than I should have done, sorry
<enebo[m]1>
looks ok to me so long as behaviorally it should be doing all that write does
<enebo[m]1>
you have one set of tests which seems to point out some encoding at least
<headius[m]>
yeah it should be the same logic as before but now it encodes the string with the right encoding
<enebo[m]1>
I also have wondered whether any specs or mri tests are tagged over this
<headius[m]>
the PR just honors the encoding you created the IOOutputStream with
<headius[m]>
so it is basically saying an intent to provide bytes encoded as X but we lost that in the old logic
<headius[m]>
it is a writer really but writers are lame because they have to be String
<enebo[m]1>
lol
<enebo[m]1>
This is API
<enebo[m]1>
I thought this was some stream_copy thing in Ruby
<headius[m]>
I am not sure of any places in JRuby itself that we use this IOOutputStream with a real IO
<headius[m]>
usually we only use it when we can't get an actual IO, like in copy_stream with weird inputs
<headius[m]>
copy_stream does not use this if the given io is really an IO
<headius[m]>
actually it might be using it for anything not a file
<headius[m]>
so that could be one place
<enebo[m]1>
If it is mostly used by exts then we will not know what they expect but perhaps in case of yaml we do know they expect something other than what we do
<enebo[m]1>
If it does bleed into a ruby method then we maybe have a mechanism to test it
<enebo[m]1>
I realize now I did not know what it was for but without knowing that I would have assumed encoding would be preserved
<enebo[m]1>
in the same way any IO would be
<headius[m]>
yeah exactly
<headius[m]>
it is just totally broken because one path treats incoming bytes as the requested encoding and the other path treats them as ASCII-8BIT
<headius[m]>
unless you have an unencoded IO it just breaks hard
<headius[m]>
well it breaks hard if you use high ascii
<headius[m]>
which is probably why it hasn't been found until now
<headius[m]>
I have one other issue for a thing we are missing but won't be implementing it today: there should be a zero-alloc path to writing byte[] into a RubyIO
<headius[m]>
given a byte[] range and encoding we should not have to construct even a ByteList to do the write
<headius[m]>
but intermediate crud like IO transcoding is written around either RubyString or ByteList (though that logic all just unwraps the bytes eventually too)
<enebo[m]1>
yeah
<headius[m]>
this could speed up a lot of places we do writes to a known IO
<headius[m]>
it is all refactoring to add such a path
<headius[m]>
just digging another call path through to the places where it actually writes byte[] to the underlying channel
<jswenson[m]>
Yeah. I attempted to do something like this through through puma and sinatra until I realized that there was nothing I could do without modifying deeper into jruby.
<headius[m]>
yeah there you go, could help a lot of exts run faster
<headius[m]>
I started to do it and the path isn't even that deep, except some heavier lifting needed on the transcoding bits
<headius[m]>
the actual write goes to byte[] pretty quickly
<headius[m]>
so many ways to speed up JRuby that have nothing to do with optimizing Ruby code. 😆
<headius[m]>
enebo: I will merge these two PRs then (IOOutputStream and env shebang)
nirvdrum has quit [Ping timeout: 245 seconds]
<enebo[m]1>
headius: ok
<headius[m]>
jswenson: I don't suppose any of you folks would have time or interest to work on that zero-alloc IO thing
<headius[m]>
if your interest is just as a user that's cool... we need it internally anywa
<jswenson[m]>
Unfortunately, no time right now. I’ll be following it though if I do get some time.