ink icon indicating copy to clipboard operation
ink copied to clipboard

Feature request: {#var: if-zero | if-one | if-two | if-three | else }

Open joningold opened this issue 8 years ago • 12 comments

This is looking increasingly useful rn; essentially an inline switch statement. I suggest using the # modifier to denote it.

The worst thing about it is

{#bool: if-false | if-true }
{ bool: if-true | if-false }

and

{#knot: if-never-seen| if-seen-once | if-seen-twice }
{knot: if-seen | if-not-seen} 

... but in both cases, the ambiguity isn't too bad, and the usefulness is (hopefully!) fairly apparent!

jon

joningold avatar Feb 03 '17 12:02 joningold

Hmm, the # character is currently used for tags. It could probably still work (since it's only checked for at the end of a valid line), but possibly confusing.

So the switch statement would only work for 0, 1, 2, 3 etc? (Because while that may be useful, it's not really an inline version of the full switch statement, it's Something Else.)

joethephish avatar Feb 03 '17 12:02 joethephish

Fair point. Right now I have a use-case for this "by index" type and it's compact. (A full switch version would be less compact

{switch var: 0: zeroth | 1: first | 2: second | else: done }

and maybe by that point is better off being multi-line. What I like about the proposed syntax is it has actually fewer characters in it. ;)

joningold avatar Feb 03 '17 12:02 joningold

Glad to hear it (if I understand correctly that this is basically following up on the discussion in #57).

The way I implement this is as an open-ended variable based on numbers, as described there. That covers really 90% of the use cases I have for this type of construct, and as mentioned there - it is a use case I see a lot in my writing. It was basically the first addition I did in jInk for that reason - it's not really a construct that I am willing to do without. As Jon notes, one of the big advantages is that it provides a very succinct way of handling "by index" text.

I could see the uses for a more powerful switch-like construct for certain use-cases even if not quite as frequently But certainly there are some use-cases where the limited index approach falls short.

If you want to look down that road, though, might I suggest a more functional programming style syntax? I must admit to finding the colon-heavy syntax pretty hard to read, especially in the first qualifier. I'd suggest instead something like:

{when expr : 0 => zeroth | 1 => first | 2 => second | else => done }

Based on the use-cases I run into, though, I'd say that you need to add combinations and ranges as switch options, before this becomes really useful. Like, e.g.:

Combination example {when expr: 1,2 => value is one or two | else -> value is something else }
Range example value is {when expr : 0 => none | 1..9 => few | 10..25 => many | else => countless }

Or even:

He was referred to as  {when name : "Blofeld" => Number 1 | "Largo" => Number 2 | else => Mr Nobody }

I use 'when' instead of 'switch' or 'match' because I'm currently working a lot with Kotlin, and it seems to me that their 'when' syntax reads more naturally in this context than the alternatives.

Just some food for thought.

micabytes avatar Feb 03 '17 14:02 micabytes

resurrecting this because it'd also be super useful for looking up display names from list values

e.g.

LIST lstListOfThings = ThingOne, ThingTwo, ThingThree

=== function GetDisplayNameForThing( valueFromListOfThings )
    ~return {LIST_VALUE(valueFromListOfThings): "Thing One!" | "Thing Two!" | "Thing Three!"}

In fact, what would be super lovely is the ability to put strings / variables into containers of some sort so you could do something like:

LIST lstListOfThings = ThingOne, ThingTwo, ThingThree
ARRAY aThingNames = "Thing One!", "Thing Two!", "Thing Three!"

=== function GetDisplayNameForThing( valueFromListOfThings )
    ~return ARRAY_INDEX( aThingNames, LIST_VALUE( valueFromListOfThings ) )

N.B. the syntax I suggest for array is a bit minging, but I guess a lot of the symbols on the keyboard are in use ;)

darbotron avatar Nov 22 '18 15:11 darbotron

My current plan is to allow list items to contain arbitrary values. Right now they're always numbers, but you could do something like:

LIST characters = bob = "Mr. Robert Mann", sue = "Ms. Susan Greenfield"

Hopefully that should be a good balance of power and ease of use!

joethephish avatar Nov 22 '18 15:11 joethephish

So, I managed a workaround for this use case which is a little meta but it seems to work fine.

Essentially you define a function which is the array then pass it to the other function.

I admit this sounds like an insane way of doing this, but I'm writing a multi story project with library code so I have something like this:

in a library file pulled in with INCLUDE

=== ThreadToInsertContextSensitiveChoice( listToCheck, listElementToCheckFor, ->FuncToGetChoiceTextFromListElement, ->TunnelToUseIfTheChoiceIsPicked, ->ReturnToHere )
    { (listToCheck ? listElementToCheckFor:
    + [{->FuncToGetChoiceTextFromListElement( listElementToCheckFor )]
        -> TunnelToUseIfTheChoiceIsPicked ->
    }
    - ->ReturnTo

then in the ink script using the library I have something like:

LIST listOfPossibleChoices = choiceOne, choiceTwo

=== function ChoiceNameFromChoice( listElement )
    { LIST_VALUE( listElement ):
    - 1:
    ~return "Choice One!"
    - 2:
    ~return "Choice Two!"
    // etc.
    }

VAR someListVariable = (ChoiceOne)

=== TunnelForChoiceOne
    Some Text! ->->

=== KnotWhichHasContextSensitiveChoices
    <- ThreadToInsertContextSensitiveChoice( someListVariable, ChoiceOne, ->ChoiceNameFromChoice, ->TunnelForChoiceOne, ->ReturnFromThread ) 
    -(ReturnFromThread)
    // ... rest of knot ...

there's way more logic in the actual stuff I have but I hope you get the idea :)

darbotron avatar Nov 22 '18 15:11 darbotron

My current plan is to allow list items to contain arbitrary values. Right now they're always numbers, but you could do something like:

LIST characters = bob = "Mr. Robert Mann", sue = "Ms. Susan Greenfield"

list elements being arbitrary values would be really helpful, for sure.

An indexed variable container would also still be super, super useful. I keep trying to think of a way to achieve it elegantly for my purposes - i.e. having the game pulling out data from the ink script.

darbotron avatar Nov 23 '18 00:11 darbotron

My current plan is to allow list items to contain arbitrary values. Right now they're always numbers, but you could do something like:

LIST characters = bob = "Mr. Robert Mann", sue = "Ms. Susan Greenfield"

Hopefully that should be a good balance of power and ease of use!

Yeah I think the "list element with string value" would help immensely, but I keep finding myself wanting / needing an indexable container type - essentially an array (or C# style "list") of variables.

So, to the earlier example I gave, the ARRAY would just be a re-sizeable box of VARs accessed by array name and index rather than individual names - a lot of what I'm trying to do would be trivially easy if I just had that simple structure to communicate between ink and my game side code.

I've actually faked this behaviour for now by doing this...

VAR FakeArray_Text_Size  = 0
VAR FakeArray_Text_1     = "One"
VAR FakeArray_Text_2     = "Two"
VAR FakeArray_Text_3     = "Three"
VAR FakeArray_Text_4     = "Four"
VAR FakeArray_Text_5     = "Five"
VAR FakeArray_Text_6     = "Six"
VAR FakeArray_Text_7     = "Seven"
VAR FakeArray_Text_8     = "Eight"
VAR FakeArray_Text_9     = "Nine"
VAR FakeArray_Text_10    = "Ten"
VAR FakeArray_Text_11    = "Eleven"
VAR FakeArray_Text_12    = "Twelve"
VAR FakeArray_Text_13    = "Thirteen"
VAR FakeArray_Text_14    = "Fourteen"
VAR FakeArray_Text_15    = "Fifteen"
VAR FakeArray_Text_16    = "Sixteen"
VAR FakeArray_Text_Over  = "Over"

// function to set the values as if they were an array
=== function TextArray_SetAt( index, value )
    {index:
    -1:     ~FakeArray_Text_1   = value
    -2:     ~FakeArray_Text_2   = value
    -3:     ~FakeArray_Text_3   = value
    -4:     ~FakeArray_Text_4   = value
    -5:     ~FakeArray_Text_5   = value
    -6:     ~FakeArray_Text_6   = value
    -7:     ~FakeArray_Text_7   = value
    -8:     ~FakeArray_Text_8   = value
    -9:     ~FakeArray_Text_9   = value
    -10:    ~FakeArray_Text_10  = value
    -11:    ~FakeArray_Text_11  = value
    -12:    ~FakeArray_Text_12  = value
    -13:    ~FakeArray_Text_13  = value
    -14:    ~FakeArray_Text_14  = value
    -15:    ~FakeArray_Text_15  = value
    -16:    ~FakeArray_Text_16  = value
    -else:  ~FakeArray_Text_Over= value
    }
    
// function to get the values as if they were an array
=== function TextArray_GetAt( index )
    {index:
    -1:     ~return FakeArray_Text_1   
    -2:     ~return FakeArray_Text_2   
    -3:     ~return FakeArray_Text_3   
    -4:     ~return FakeArray_Text_4   
    -5:     ~return FakeArray_Text_5   
    -6:     ~return FakeArray_Text_6   
    -7:     ~return FakeArray_Text_7   
    -8:     ~return FakeArray_Text_8   
    -9:     ~return FakeArray_Text_9   
    -10:    ~return FakeArray_Text_10  
    -11:    ~return FakeArray_Text_11  
    -12:    ~return FakeArray_Text_12  
    -13:    ~return FakeArray_Text_13  
    -14:    ~return FakeArray_Text_14  
    -15:    ~return FakeArray_Text_15  
    -16:    ~return FakeArray_Text_16  
    -else:  ~return FakeArray_Text_Over
    }

darbotron avatar Dec 05 '18 09:12 darbotron

That's a good work around; we use "database functions" a lot for static information. There's a post on our Patreon ( https://www.patreon.com/posts/tips-and-tricks-19789721) with code for a "list linker", which might help in more dynamic cases; it lets you set up a pairs of the form (A, X), where A comes from a list A, B, C and X comes from X, Y, Z. Since X, Y, Z could be a list with the values "1, 2, 3..." you can use that to make a flexible array-ish structure.

Arrays would still be useful, of course!

On Wed, Dec 5, 2018 at 9:59 AM darbotron [email protected] wrote:

My current plan is to allow list items to contain arbitrary values. Right now they're always numbers, but you could do something like:

LIST characters = bob = "Mr. Robert Mann", sue = "Ms. Susan Greenfield"

Hopefully that should be a good balance of power and ease of use!

Yeah I think the "list element with string value" would help immensely, but I keep finding myself wanting / needing an indexable container type - essentially an array (or C# style "list") of variables.

So, to the earlier example I gave, the ARRAY would just be a re-sizeable box of VARs accessed by array name and index rather than individual names - a lot of what I'm trying to do would be trivially easy if I just had that simple structure to communicate between ink and my game side code.

I've actually faked this behaviour for now by doing this...

VAR FakeArray_Text_Size = 0 VAR FakeArray_Text_1 = "One" VAR FakeArray_Text_2 = "Two" VAR FakeArray_Text_3 = "Three" VAR FakeArray_Text_4 = "Four" VAR FakeArray_Text_5 = "Five" VAR FakeArray_Text_6 = "Six" VAR FakeArray_Text_7 = "Seven" VAR FakeArray_Text_8 = "Eight" VAR FakeArray_Text_9 = "Nine" VAR FakeArray_Text_10 = "Ten" VAR FakeArray_Text_11 = "Eleven" VAR FakeArray_Text_12 = "Twelve" VAR FakeArray_Text_13 = "Thirteen" VAR FakeArray_Text_14 = "Fourteen" VAR FakeArray_Text_15 = "Fifteen" VAR FakeArray_Text_16 = "Sixteen" VAR FakeArray_Text_Over = "Over"

// function to set the values as if they were an array === function TextArray_SetAt( index, value ) {index: -1: ~FakeArray_Text_1 = value -2: ~FakeArray_Text_2 = value -3: ~FakeArray_Text_3 = value -4: ~FakeArray_Text_4 = value -5: ~FakeArray_Text_5 = value -6: ~FakeArray_Text_6 = value -7: ~FakeArray_Text_7 = value -8: ~FakeArray_Text_8 = value -9: ~FakeArray_Text_9 = value -10: ~FakeArray_Text_10 = value -11: ~FakeArray_Text_11 = value -12: ~FakeArray_Text_12 = value -13: ~FakeArray_Text_13 = value -14: ~FakeArray_Text_14 = value -15: ~FakeArray_Text_15 = value -16: ~FakeArray_Text_16 = value -else: ~FakeArray_Text_Over= value }

// function to get the values as if they were an array === function TextArray_GetAt( index ) {index: -1: ~return FakeArray_Text_1 -2: ~return FakeArray_Text_2 -3: ~return FakeArray_Text_3 -4: ~return FakeArray_Text_4 -5: ~return FakeArray_Text_5 -6: ~return FakeArray_Text_6 -7: ~return FakeArray_Text_7 -8: ~return FakeArray_Text_8 -9: ~return FakeArray_Text_9 -10: ~return FakeArray_Text_10 -11: ~return FakeArray_Text_11 -12: ~return FakeArray_Text_12 -13: ~return FakeArray_Text_13 -14: ~return FakeArray_Text_14 -15: ~return FakeArray_Text_15 -16: ~return FakeArray_Text_16 -else: ~return FakeArray_Text_Over }

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/inkle/ink/issues/262#issuecomment-444427547, or mute the thread https://github.com/notifications/unsubscribe-auth/AA40oyQ7HBYzs4IRPTSg1BSUtPmEfOdBks5u15jqgaJpZM4L2Rcq .

joningold avatar Dec 05 '18 10:12 joningold

Sorry to resurrect this ancient issue, but did anything come of this? I don't see the when syntax in the documentation. How best would you write: It was a beautiful {getDayPhaseAsInt(): morning | afternoon | evening | night}.

shouldice avatar Nov 12 '23 14:11 shouldice

you could do something like:

It was a beautiful <>
{getDayPhaseAsInt():
    -1:     morning
    -2:     afternoon
    -3:     evening
    -4:     night
}

darbotron avatar Nov 12 '23 17:11 darbotron

Thanks! I guess the hyper-concise/inline version of this never made it into the syntax, but this is still valuable; thank you!

shouldice avatar Nov 12 '23 17:11 shouldice