+def Cat(*args, src_loc_at=0):
+ """Concatenate values.
+
+ Behaviour is required to be identical to _InternalCat.
+ The first argument "defines" the way that all others are
+ handled. If the first argument is derived from UserValue,
+ it is not downcast to a type Value because doing so would
+ lose the opportunity for "redirection" (Value.__Cat__ would
+ always be called).
+ """
+ # flatten the args and convert to tuple (not a generator)
+ args = tuple(flatten(args))
+ # check if there are no arguments (zero-length Signal).
+ if len(args) == 0:
+ return _InternalCat(*args, src_loc_at=src_loc_at)
+ # determine if the first is a UserValue.
+ if isinstance(args[0], UserValue):
+ first = args[0] # take UserValue directly, do not downcast
+ else:
+ first = Value.cast(args[0]) # ok to downcast to Value
+ # all other arguments are safe to downcast to Value
+ rest = [Value.cast(v) for v in flatten(args[1:])]
+ # assume first item defines the "handling" for all others
+ return first.__Cat__(*rest, src_loc_at=src_loc_at)
+
+
+class _InternalCat(Value):