Why is this reimplementation in Strategy Game Example?

In the Strategy Game Example, all interfaces implemented like this. Why?

UINTERFACE()
class UStrategyInputInterface : public UInterface
{
	GENERATED_UINTERFACE_BODY()
};

class IStrategyInputInterface
{
	GENERATED_IINTERFACE_BODY()

	/** receive input: tap */
	UFUNCTION(BlueprintNativeEvent)
	void OnInputTap();

	/** receive input: hold */
	UFUNCTION(BlueprintNativeEvent)
	void OnInputHold();

	/** receive input: hold released */
	UFUNCTION(BlueprintNativeEvent)
	void OnInputHoldReleased(float DownTime);

	/** receive input: swipe update (world space, not screen space)*/
	UFUNCTION(BlueprintNativeEvent)
	void OnInputSwipeUpdate(const FVector& DeltaPosition);

	/** receive input: swipe finished (world space, not screen space) */
	UFUNCTION(BlueprintNativeEvent)
	void OnInputSwipeReleased(const FVector& DeltaPosition, float DownTime);
};

Couldn’t it be like this?

UINTERFACE()
class IStrategyInputInterface : public UInterface
{
	GENERATED_IINTERFACE_BODY()

	/** receive input: tap */
	UFUNCTION(BlueprintNativeEvent)
	void OnInputTap();

	/** receive input: hold */
	UFUNCTION(BlueprintNativeEvent)
	void OnInputHold();

	/** receive input: hold released */
	UFUNCTION(BlueprintNativeEvent)
	void OnInputHoldReleased(float DownTime);

	/** receive input: swipe update (world space, not screen space)*/
	UFUNCTION(BlueprintNativeEvent)
	void OnInputSwipeUpdate(const FVector& DeltaPosition);

	/** receive input: swipe finished (world space, not screen space) */
	UFUNCTION(BlueprintNativeEvent)
	void OnInputSwipeReleased(const FVector& DeltaPosition, float DownTime);
};

Hi,

We have considered it, and it’s something we’d like to see improved for teachability reasons, but there are a few technical/logical challenges to meet before that happens.

  • UInterface holds the metadata of the interface, which is state. This is in contradiction to the usually-stateless model of interfaces.
  • An IInterface is not a UObject and UInterface is, and so having IInterfaces derive from UInterface (and thus UObject) would break the cosmic hierarchy that the UObject system assumes, as you’d then have multiple UObject bases per type.
  • The UInterface type needs to be instantiatable by itself, which is incompatible with some types of IInterface definitions.

It’s more likely that you wouldn’t inherit anything (unless you were extending another interface, or you’d inherit IInterface). However, we still need the UInterface type because it’s tied to the whole UObject system.

  • The UInterface could be generated by UnrealHeaderTool, but sometimes you need to refer to it in native code, and then you have visibility issues around where this ‘magic’ UStrategyInputInterface type appears from, as there is no reference to it in the source.
  • UnrealHeaderTool would need to be reworked to recognise UInterfaces vs. non-UInterfaces in order to correctly determine dependencies, which touches upon the (current) need to prefix everything with a correct prefix. For example, if I have an IWidget object name, is that supposed to be a UClass called UIWidget, or a Widget interface?

A lot of this stuff is legacy and are not insurmountable, but they’re not trivial to solve either. As I say it’s certainly on our radar, but not high on our priority lists right now.

Steve

The UInterface part could just be generated in top of the file. It’s just a chunk of junk code that must be there, or at least that’s how it looks from the user perspective.

Also, I really think you should consider at EPIC to make “unreal interfaces” possible to use as “U” properties. This is something I feel really limiting the design possibilities in the engine right now, making development much harder and resulting in dirty code. In the current design the biggest advantages of interfaces are totally missed. The abstraction interfaces provide are invaluable. Interfaces are now just used to dynamically cast different types to see if we can perform different actions.

Thanks for the detailed answer.

The UInterface part could just be generated in top of the file. It’s just a chunk of junk code that must be there, or at least that’s how it looks from the user perspective.

I covered this above. Yes, it ‘could just be’, but identifiers which come into being by magic are not considered a desirable feature. We have to consider any impact to all users by making such a change.

Also, I really think you should consider at EPIC to make “unreal interfaces” possible to use as “U” properties.

Oh, it has been considered, and is continuing to be. But there are technical challenges in the garbage collector and property system to solve before this can happen as naturally as it can for UObject* properties.

You can use TScriptInterface in the meantime as a workaround, as I mentioned on your original thread on the subject:

Steve

Had not seen your reply yet. Sounds very interesting. Thanks!