List Concatenation of Different Types


#1

I was trying to build a dynamic list of actors to ignore for a line trace:

!result? : SystemLib.line_trace_single_for_objects(
    @@world
    start
    end
    {EObjectTypeQuery.@@object_type_world_static, EObjectTypeQuery.@@object_type_vehicle}
    actors_to_ignore : BP_LapProgress.instances + BP_RacingPowerup.instances)

I thought that BP_LapProgress.instances + BP_RacingPowerup.instances should compile but it doesn’t. Now I notice that:

{1 2 "three"} + {"four" "five" "six"} // compiles
{1 2 3} + {"four" "five" "six"} // doesn't compile

So maybe this is also by design where only lists of the same type are meant to be added together.

My work-around right now:

!l : {}
l.appending(BP_LapProgress.instances)
l.appending(BP_RacingPowerup.instances)

List manipulation enhancements
#2

This is by design. Only lists of compatible types can be added together.

!nums: {1 2 3}
!strs: {"one" "two" "three"}
!numstrs: nums + strs  // Integer and String are not compatible

If you don’t care about the list item type you can use Object as an item type and do the following:

!nums: {1 2 3}
!strs: {"one" "two" "three"}

// Make an empty list and append to it
// Brackets needed to ensure correct order
!numstrs1: [{} += nums] += strs
// Basically the same using method instead of operator
!numstrs2: {}.append_list(nums).append_list(strs)
// Start with copy and add to it
!numstrs3: List!copy(nums).append_list(strs)

If you do care about the type you can use a union type which is more specific.
In this case <Integer|String> and in your case it could be Actor.

!nums: {1 2 3}
!strs: {"one" "two" "three"}

// Make an empty list and append to it
// Brackets needed to ensure correct order
// You could use just + though += adds onto the existing list
!numstrs1: [List{<Integer|String>}! += nums] += strs
// Basically the same using method instead of operator
!numstrs2: List{<Integer|String>}!.append_list(nums).append_list(strs)
// Start with copy and add to it
!numstrs3: List{<Integer|String>}!copy(nums).append_list(strs)

We could also add a concatenation constructor that would look like this:

!nums: {1 2 3}
!strs: {"one" "two" "three"}

// Untyped (Ojbect)
!numstrs1: List!join(nums strs)
// Typed (Ojbect)
!numstrs2: List{<Integer|String>}!join(nums strs)

Just let us know if you want us to add this or see if you can make your own.

Calling appending() should just add a list as an item rather than adding each item individually. You probably want to use append_list() instead.

So for your case, you might want to use:

[Actor{} += BP_LapProgress.instances] += BP_RacingPowerup.instances
// or
Actor{}.append_list(BP_LapProgress.instances).append_list(BP_RacingPowerup.instances)
// or starting with copy
List{Actor}!copy(BP_LapProgress.instances) += BP_RacingPowerup.instances
// or if List!join() were available
List{Actor}!join(BP_LapProgress.instances BP_RacingPowerup.instances)

Typed lists can be tricky. Take a look at the List doc page for examples.

Let me know if this helps.


#3

Thanks this helps. I see now that my previous work-around was creating a list of objects rather than a list of actors.


#4

Going for the shortest version - good choice. :madsci:

The brackets are a bit annoying, though without them the parser sees this:

Actor{} += BP_LapProgress.instances += BP_RacingPowerup.instances

as this:

Actor{} += [BP_LapProgress.instances += BP_RacingPowerup.instances]

And they would be incompatible List item types.


#5

p.s. There are some future parser enhancements for List that would be nice in this situation.


#6

To get around the brackets we could easily make a List@join() method that would keep the same list type and allow several lists to be appended at once.

So instead of this:

[Actor{} += BP_LapProgress.instances] += BP_RacingPowerup.instances

you would use:

Actor{}.join(BP_LapProgress.instances BP_RacingPowerup.instances)

Instead of join() the method name could alternatively be append_lists() or something similar.

Thinking about it more, If adding all instances of a class is super common we could even do this

// Make a list of Actors with instances from the specified classes
// Type would be List{Actor}
Actor.instances_of(BP_LapProgress BP_RacingPowerup)

Feel free to recommend a better name than instances_of(): list_of(), all_of(), list().

What do you think?


#7

I like this!

This looks very pleasing. I think I’d prefer list_of() or maybe list_from() or instances_from().


#8

Okay great.

I’ll add them.

Until then, you could either use the [] += mechanism or make the above methods yourself - it should be pretty easy at least in script form.


#9

I ended up calling the first fuse() to keep it short and taking into consideration list libraries in other languages.

Actor{}.fuse(BP_LapProgress.instances BP_RacingPowerup.instances)

It’s method looks like this:

// instance method List@fuse()
({ThisClass_} lists) ThisClass_
  [
  lists.do[append_list(item)]
  this
  ]

I ended up calling the second instances_from() so that it is grouped with the other instance methods.

Actor.instances_from(BP_LapProgress BP_RacingPowerup)

It’s method looks like this:

// class method Actor@instances_from()
({<ThisClass_>} classes) List{ThisClass_}
  [
  !list: ThisClass_{}
  classes.do[list.append_list(item.instances)]
  list
  ]

Pretty simple really for fairly sophisticated routines. :madsci:

They’ll be in the next update.