3

The IN function in Rebol finds out if a field is in an object:

USAGE:
    IN object word

DESCRIPTION:
    Returns the word or block in the object's context.
    IN is a native value.

ARGUMENTS:
    object (any-object! block!)
    word -- (modified if series) (any-word! block! paren!)

The claim is it works with objects or blocks. It works okay if I try it with an object:

>> in object [foo: 10 bar: 20] 'foo
== foo

But if I just try it with a raw block, it gives back NONE:

>> in [foo: 10 bar: 20] 'foo
== none

Guess I'd understand if it didn't support blocks (Rebol2 didn't). But what's the case in which it wouldn't return NONE that blocks are allowed for?

And at the risk of making this two questions in one, what's the deal with accepting BLOCK! for the word parameter? I'd think it would take a block if you had a set of words you were looking for, but it seems to just return the block:

>> in object [foo: 10 bar: 20] [mumble frotz bar]
== [mumble frotz bar]

>> in object [foo: 10 bar: 20] [mumble frotz]
== [mumble frotz]

And at the further risk of making this three questions, what meaning would taking a PAREN! for word have?

earl
  • 40,327
  • 6
  • 58
  • 59
  • Is this new behaviour in rebol3? I can't seem to use a block in either rebol2 or red: `** Script Error: in expected object argument of type: object port ** Near: in [foo: 10 bar: 20] 'foo` – Geeky I Oct 01 '16 at 16:06
  • @GeekyI It would appear to not be in Rebol2. But Red 0.6.1 seems to accept blocks as parameters...although it has what appears to be the wrong result. `obj: make object! [a: 10 b: 20 c: 30]` and then `in obj [a c]` returns the object instead of the rebound block. You might raise an issue on their tracker to clarify the intent. – HostileFork says dont trust SE Oct 01 '16 at 22:57
  • I just realized this is 3 questions in 1, thus the confusion :-p, I meant the 1st question (so uh.. I can't @mention anyone yet..?) – Geeky I Oct 01 '16 at 23:02
  • *(@GeekyI mentions to the OP are elided if that's the only person you're talking with, as the OP is always notified when comments appear on their questions.)* => I didn't read your error closely enough. You can't say IN BLOCK! WORD! in any of the interpreters...a block is not a context to find words in. You can say IN OBJECT! BLOCK! in Rebol3, and yes that is a new feature. – HostileFork says dont trust SE Oct 01 '16 at 23:27

2 Answers2

5

The IN function isn't primarily meant for searching an object for a word, it is for returning a word or block of words that are in the object, or in Rebol terms bound to the object. It's a variant of the BIND function that is useful in different circumstances than BIND.

If there is no word of that name in the object, it returns none, sensibly enough. This gives it the side benefit of being able to be used in conditional expressions as a word detection function, but that's not its main use.

IN can take a block of objects for its object parameter and then try to bind the word to each object in turn, returning a word bound to the first object in the block that has that word. This was meant as a relatively quick way to do overriding word lookup for an old design of the Rebol 3 GUI, but it turned out to not be the best approach in that case so the GUI doesn't use that design now. However, IN block word was kept as a potentially useful feature for future use elsewhere.

In your example, there were no objects in that block, so there was nothing that IN could bind the word to. That is why IN returned none.

If you pass IN a block for the word parameter, it binds the block to the object before it returns it. This is to allow code like do in obj [print a]. It doesn't do a bind/copy though, so you should be careful about code like that. Or maybe IN object block should copy - is it too late to change that? Passing a paren for the word argument should have the same binding behavior as passing a block.

When last I checked, we didn't support having both the object an word parameters be blocks. This is because we couldn't figure out a good model for what that behavior should be, at least obviously. The overriding word lookup doesn't really work with a block of words because the results would be inconclusive.

It would be useful to have a function that rebound a block to a series of objects in order, especially for recreating Rebol's not-really-nested scopes, but it would be really confusing for that function to be IN.

BrianH
  • 2,186
  • 16
  • 14
  • So to make a long story short: *FIND is polymorphic and returns LOGIC! of "is key in object", while IN is related to BIND voodoo...and not what you might think it does because of the name.* I think what worries me here is that with FIND being so different for block and object, it would be safer if "has key" was a separate thing to prevent accidents. Maybe HAS could be repurposed for things that return boolean results (not a very good word for something that makes functions, IMO)...and FIND always return series positions? Even with polymorphism abilities, one should have invariants. – HostileFork says dont trust SE Jan 12 '14 at 17:19
  • I'm not going to get into a flame war about what should have been, so let's just focus on what is, for a moment. FIND is polymorphic because it is an action, and only actions or wrappers for actions are polymorphic in Rebol. Natives that don't call actions internally aren't polymorphic. IN is a preposition, so the function was intended for circumstances where you would use it in English, like `get in obj 'a` or `set in obj 'a 200` or `do in obj [something]`. The main reason it exists at all is code clarity, or else we could just use BIND. It doesn't make sense to use IN on its own. – BrianH Jan 13 '14 at 01:30
2

This might not be as useful, but since it is not explicitly mentioned, and I think is the 'right' way to solve your first question for now:

red>> first find [foo: 10 bar: 20] 'foo
== foo:

This doesn't work on rebol2 tho, but quoteing the set-word! does :

>> first find [foo: 10 bar: 20] quote [foo:]
== foo:

Still has the slight disadvantage of returning a set-word!

Geeky I
  • 751
  • 6
  • 22
  • 1
    Yes, FIND is the correct operation to check when something is in a block. The question (and its answer) ultimately relate to the issue of what IN is. Years later after this question is asked, I understand its purpose as an inversion of BIND's parameter order....not a form of FIND. – HostileFork says dont trust SE Oct 01 '16 at 23:30
  • @HostileFork the problem then is that `in` can be a newbie mistake for `has-key`. Actually, as a more generic *contains* like the `in` keyword of python – Geeky I Oct 01 '16 at 23:38
  • 1
    Yup, I understand the confusion (as I had it too). But it turns out this definition of IN has broad applications. Instead of `foo/method1 a b | foo/method2 c d | foo/method3 e f` you can say `do in foo [method1 a b | method2 c d | method3 e f]` (well, assuming no a,b,c,d,e,f in foo!). Perhaps if the error message were more informative to guide people to FIND if they tried to use a block as the place to look, it could be the best of both worlds? – HostileFork says dont trust SE Oct 02 '16 at 00:34