red / REP

Red Enhancement Process
BSD 3-Clause "New" or "Revised" License
11 stars 4 forks source link

WISH: `in func any-word` to preserve the found word type #160

Open hiiamboris opened 9 months ago

hiiamboris commented 9 months ago

Currently all slippers look the same:

>> in f: func [x][] 'x
== x
>> in f: func [/x][] 'x
== x
>> in f: func [/x][] /x
== x
>> in f: func [x][] /x
== x

So when I want to test if function f supports refinement /x, I don't have a fast and reliable way of doing that, because I may use a x: ... in the function which will be converted to a /local x, and in test will succeed.

What I'm proposing:

>> in f: func [x][] 'x
== x
>> in f: func [/x][] 'x
== /x
>> in f: func [/x][] /x
== /x
>> in f: func [x][] /x
== x
>> in f: func [:x][] 'x
== :x
>> in f: func ['x][] 'x
== 'x

So /x == in :f /x could then be used to be certain it's a refinement.

greggirwin commented 9 months ago

My first instinct was YES, but then we have to consider that set/get don't work with refinements, so it changes some cases where you would normally only check for none? in .... Index? and context? as well.

hiiamboris commented 9 months ago

You don't set/get a word in a spec of a function you haven't called yet, so should not be an issue ;)

it changes some cases where you would normally only check for none? in .... Index? and context? as well.

I didn't catch that (maybe because it's late ;), could you elaborate?

greggirwin commented 9 months ago

Today it either returns the word or none, so you might do

>> obj: object [x: 1]
== make object! [
    x: 1
]
>> if w: in obj 'x [set w 2]
== 2

Which is still fine for objects. For functions, even if it returns the type given, that helps for refinements, but won't tell you if something is an arg or local. Thinking about it might be used, and where you aren't using a literal arg with in, so may not know if it's a word or refinement.

Once you're working inside the function, context? works, but where you would normally just use x in code, whether it's a refinement or not. Now context? would also need to support refinements.

hiiamboris commented 9 months ago

OK. I do not propose context? to support refinements, or in obj to behave differently. Just in func.

dockimbel commented 9 months ago

The purpose of in is:

So what you are proposing would break the basic purpose of in, as refinements can't be bound to a context.

Eventually, your wish could be implemented as a new refinement to in, like /keep. Though, it would be hard to remember that in/keep is there to actually check if a refinement is defined or not...

If the goal is to check if a given function supports a given refinement, maybe we should rather consider extending reflect on function! for that need?

hiiamboris commented 9 months ago

Though I don't see how this wish contradicts the stated goals, I don't mind in/keep or reflect solutions. This is a rare need, so particular interface is of tiny importance. I don't envision however how reflect can fit this need better. It's designed as reflect value field, where field is one of the predefined categories, not a specific word from the spec.

greggirwin commented 9 months ago

Let's come back to the original use case: " I want to test if function f supports refinement /x"

What's wrong with mezz level?

refinement-in: func [
    fn [any-function!]
    ref [refinement!]
][
    find spec-of :fn ref
]

This should be reliable, and reasonably fast.

>> clock/times [refinement-in :find /match] 10'000
1.30 μs [refinement-in :find /match]
greggirwin commented 9 months ago

find-refinement would be a better name there.

hiiamboris commented 9 months ago

That was my initial approach until @dockimbel was so kind to implement a more optimal option :) But I have now to test each created style and want if it contains one of the supposed-to-be refinements as a local. I don't want to go once again into the "it's fast enough in my console" argument with you ;)