Interface Type: Difference between revisions

From Resonite Wiki
m typo
overhaul
Line 1: Line 1:
Interface types are [[Reference Type|reference types]] that don't refer to a specific [[:Category:Type|Type]], but a [https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/interface C# Interface] that can be implemented by one or multiple component classes. Interfaces are used to describe a specific common behavior that similar classed may want to implement. Because clases that implement a specific interface are required to implement the methods and properties defined in that interface, they can all be assigned to a variable of the interface type, making them very userful within Resonite.
An '''interface type''' is a [[Reference Type]] that does not necessarily refer to a specific type that can be instantiated, but rather a contract of sorts. Any type that "implements" the interface must provide an implementation of whatever is defined within the interface or fall back to a default implementation on the interface itself. They are used to describe a specific common behavior that classes of a similar kind can implement to avoid code duplication. Types may implement multiple interfaces at once.
 
Within [[FrooxEngine]], interfaces are extensively used for nearly every single type. For example, every [[Reference Type]] implements the [[Type:IWorldElement|IWorldElement]] interface. A common convention, and the convention used within FrooxEngine, is for all interfaces type names to start with a capital <code>I</code>.
 
== Shared Behavior ==
Because interfaces represent shared behavior across all implementations of the interface, they can be leveraged to provide generic behavior across many different, yet similar types.
 
For example, [[ProtoFlux:Source|Source]] nodes retrieve the value of any object that implements the [[Type:IValue|IValue<T>]] type matching the node. This allows for a [[Type:float|float]] source to get the output of an [[Component:AuthorityTimeBase|AuthorityTimeBase]], [[Component:ValueMultiplexer|ValueMultiplexer<float>]], or any float fields in general, despite these three instances strictly being separate types.


== Casting ==
== Casting ==
Interfaces can be casted into a specific variant of what they can possibly wrap, and the cast will try to represent the interface as a non interface type
Objects of a specific type can be cast to and from any interface type they implement, just like with their potential derived type. This can be leveraged with the shared behavior property to make generic implementations for specific types.
 
For example, you can't cast the contents of an [[Type:IComponent|IComponent (interface)]] storing an [[ObjectRoot (Component)|ObjectRoot]] into a [[CopyGlobalTransform (Component)|CopyGlobalTransform]] or it will give null. You also can't cast an [[Type:IButton|IButton's]] contents into a [[Type:SyncPlayback|SyncPlayback]] because a SyncPlayback would never fit under the [[Type:IButton|IButton]] interface. A [[Type:SyncPlayback|SyncPlayback]] is a playable not a button, essentially.


{{Note|In C# it is convention to start interface class names with the capital letter 'I'.|information}}
For example, any [[Component|component]] can be cast to an [[Type:IComponent|IComponent]], but only components matching the requested type can be cast from an IComponent to the component type. You can cast an [[Component:ObjectRoot|ObjectRoot]] to IComponent, but you can't cast the resulting IComponent reference into a [[Component:Grabbable|Grabbable]] component.


== Example ==
== See Also ==
An example of an interface type used within Resonite is [[Type:IButton|IButton]]. It is implemented by multiple button-like components like [[Button (Component)|Button]], [[PhysicalButton (Component)|PhysicalButton]] and [[TouchButton (Component)|TouchButton]]. All of those components implement the behavior of a '''''button that can be pressed''''' as defined in [[Type:IButton|IButton]]. Because of this, you can use either of them as a valid reference to plug into the "Button" input of the [[Button Events (ProtoFlux)|Button Events ProtoFlux node]], which requires a [[ProtoFlux:Global|global]] of type [[Type:IButton|IButton]].
* [https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/interface Microsoft documentation on C# interfaces]

Revision as of 00:21, 17 August 2024

An interface type is a Reference Type that does not necessarily refer to a specific type that can be instantiated, but rather a contract of sorts. Any type that "implements" the interface must provide an implementation of whatever is defined within the interface or fall back to a default implementation on the interface itself. They are used to describe a specific common behavior that classes of a similar kind can implement to avoid code duplication. Types may implement multiple interfaces at once.

Within FrooxEngine, interfaces are extensively used for nearly every single type. For example, every Reference Type implements the IWorldElement interface. A common convention, and the convention used within FrooxEngine, is for all interfaces type names to start with a capital I.

Shared Behavior

Because interfaces represent shared behavior across all implementations of the interface, they can be leveraged to provide generic behavior across many different, yet similar types.

For example, Source nodes retrieve the value of any object that implements the IValue<T> type matching the node. This allows for a float source to get the output of an AuthorityTimeBase, ValueMultiplexer<float>, or any float fields in general, despite these three instances strictly being separate types.

Casting

Objects of a specific type can be cast to and from any interface type they implement, just like with their potential derived type. This can be leveraged with the shared behavior property to make generic implementations for specific types.

For example, any component can be cast to an IComponent, but only components matching the requested type can be cast from an IComponent to the component type. You can cast an ObjectRoot to IComponent, but you can't cast the resulting IComponent reference into a Grabbable component.

See Also