Members
Forms that compile (43)
Section titled “Forms that compile (43)”| Syntax | Description |
|---|---|
private int count; | Field |
private int count = 5; | Declaration with initializer |
private const int Max = 10; | Constant |
private static int Count; | Static field |
private static readonly int Max = 10; | Static readonly field |
private void Do() | Method declaration |
private int Get() | Method with a return value |
private int Add(int a, int b) | Method with parameters |
int Add(int a, int b = 2) | Default argument |
Add(b: 2, a: 1) | Named argument |
Add(int, int) / Add(float, float) | Overload |
private int Twice(int n) => n * 2; | Expression-bodied method |
private static int Zero() | Static method |
public int Value { get; set; } | Auto-property |
public int Doubled { get { return n * 2; } } | Computed property |
{ get; private set; } | Different accessibility for get and set |
{ get; set; } = 1; | Property initializer |
{ get; } | Getter-only auto-property |
{ get; init; } | init accessor |
[field: SerializeField] | Attribute on the backing field |
public virtual int V { get { … } } | Virtual property |
public int this[int i] | Indexer |
this[0] = 3; | Writing to an indexer |
public event System.Action Fired; | event declaration |
event … { add { } remove { } } | Writing subscribe/unsubscribe accessors |
~C() { } | Finalizer |
private volatile int V; | volatile |
public readonly int Read() | readonly member of a value type |
Add(1) / Add(1, 2) | Selection by argument count |
Show(1) / Show("a") | Selection by argument type |
Show(int) が Show(long) に勝つ | Preference for the candidate with fewer conversions |
Sum(1, 2) | Expansion into a variable-length argument |
Sum(int,int) が params に勝つ | Preference for the normal candidate |
Add(1) | Omitting a default argument |
Pick(1, 2) | Inference from arguments |
First(new int[] { 1 }) | Inference from array elements |
Left(1, "a") | Inference of two type parameters |
Depth(new int[1][]) | Inference from a nested array |
true ? 1 : 2L | Common type from both sides of ?: |
public struct Inner { ... } | Nested type |
public partial class C | Type written in parts |
abstract int Get(); / override | Implementing an abstract method |
virtual int Get() / override | Overriding a default implementation |
Forms that don’t compile (9)
Section titled “Forms that don’t compile (9)”| Syntax | Description | Error | Reason | Instead |
|---|---|---|---|---|
public class Base : TsukimiBehaviour ... public class Leaf : Base | Inherit from a concrete type | TUKI0109 | undecided | Make the base abstract |
Fired?.Invoke() | Notify with event | TUKI0108 | runtime | Call the method directly, or send it by specifying a name |
Fired += Handler | Subscribe to event | TUKI0108, TUKI0099 | runtime | Same as above |
public static extern int Native() | Declare an extern implementation | TUKI0001 | runtime | Call a method on the runtime |
Read(int v) と Read(in int v) を並べる | Distinguish candidates by how the argument is passed | TUKI0001 | undecided | Rename it. in alone can be used (Variables and argument passing) |
public int Twice { get { … } set { … } }(struct の中) | Writable computed property (value type) | TUKI0001 | not yet | Use get only, or make it a method (struct and record) |
public int Extra { get; set; }(record の中) | Property (record) | TUKI0001 | by design | Use a positional parameter, or make it a method |
c[0] = 1;(struct の中の添字) | Writing to an indexer (value type) | TUKI0001 | not yet | Make it a method that returns a new value, or use an indexer on the behaviour |
panel[0](別のふるまいの添字) | Read an indexer on another behaviour | TUKI0001 | undecided | Put a method on the other side and call it |
For event, only the declaration compiles. A line written as Fired += Handler and a line written as Fired?.Invoke() both produce TUKI0108. |
~C() and volatile compile and run. No error or warning appears, but writing them does not change behaviour. Members that initialize the type itself (static constructors, module initializers) do not run either (Initialization and execution order).
Whether a property compiles depends on where it’s placed and the shape of its accessors.
| Where it’s placed | Auto-property | Computed (get only) | Computed (with set) |
|---|---|---|---|
| Behaviour | Compiles | Compiles | Compiles |
struct | Compiles | Compiles | Doesn’t compile |
record | Doesn’t compile | Doesn’t compile | Doesn’t compile |
| Interface | Compiles (the implementing side must also use an auto-property) | Doesn’t compile | — |
using UnityEngine;using Tsukimi;
public class MemField : TsukimiBehaviour{ private int count;
void Start() { Debug.Log(count); // => 0 }}Declaration with initializer
Section titled “Declaration with initializer”using UnityEngine;using Tsukimi;
public class MemFieldInitializer : TsukimiBehaviour{ private int count = 5;
void Start() { Debug.Log(count); // => 5 }}Constant
Section titled “Constant”using UnityEngine;using Tsukimi;
public class MemConst : TsukimiBehaviour{ private const int Max = 10;
void Start() { Debug.Log(Max); // => 10 }}Static field
Section titled “Static field”Reads and writes without creating an instance. The value is separate per behaviour instance and is not shared between instances.
using UnityEngine;using Tsukimi;
public class MemStaticField : TsukimiBehaviour{ private static int Count;
void Start() { Count = 1; Debug.Log(Count); // => 1 }}Static readonly field
Section titled “Static readonly field”static readonly compiles, but it doesn’t for a struct type (struct and record).
using UnityEngine;using Tsukimi;
public class MemStaticReadonly : TsukimiBehaviour{ private static readonly int Max = 10;
void Start() { Debug.Log(Max); // => 10 }}Methods
Section titled “Methods”Method declaration
Section titled “Method declaration”using UnityEngine;using Tsukimi;
public class MemMethod : TsukimiBehaviour{ private void Do() { Debug.Log(1); } // => 1
void Start() { Do(); }}Method with a return value
Section titled “Method with a return value”using UnityEngine;using Tsukimi;
public class MemMethodReturn : TsukimiBehaviour{ private int Get() { return 1; }
void Start() { Debug.Log(Get()); // => 1 }}Method with parameters
Section titled “Method with parameters”using UnityEngine;using Tsukimi;
public class MemMethodParameters : TsukimiBehaviour{ private int Add(int a, int b) { return a + b; }
void Start() { Debug.Log(Add(1, 2)); // => 3 }}Default argument
Section titled “Default argument”using UnityEngine;using Tsukimi;
public class MemDefaultArgument : TsukimiBehaviour{ private int Add(int a, int b = 2) { return a + b; }
void Start() { Debug.Log(Add(1)); // => 3 }}Named argument
Section titled “Named argument”using UnityEngine;using Tsukimi;
public class MemNamedArgument : TsukimiBehaviour{ private int Add(int a, int b) { return a + b; }
void Start() { Debug.Log(Add(b: 2, a: 1)); // => 3 }}Overload
Section titled “Overload”using UnityEngine;using Tsukimi;
public class MemOverload : TsukimiBehaviour{ private int Add(int a, int b) { return a + b; }
private float Add(float a, float b) { return a + b; }
void Start() { Debug.Log(Add(1, 2) + Add(1f, 2f)); // => 6 }}Expression-bodied method
Section titled “Expression-bodied method”using UnityEngine;using Tsukimi;
public class MemExpressionBodied : TsukimiBehaviour{ private int Twice(int n) => n * 2;
void Start() { Debug.Log(Twice(2)); // => 4 }}Static method
Section titled “Static method”using UnityEngine;using Tsukimi;
public class MemStaticMethod : TsukimiBehaviour{ private static int Zero() { return 0; }
void Start() { Debug.Log(Zero()); // => 0 }}Properties
Section titled “Properties”Auto-property
Section titled “Auto-property”using UnityEngine;using Tsukimi;
public class MemAutoProperty : TsukimiBehaviour{ public int Value { get; set; }
void Start() { Value = 1; Debug.Log(Value); // => 1 }}Computed property
Section titled “Computed property”A property whose get body you write yourself. Inside a struct, you cannot write set (struct and record).
using UnityEngine;using Tsukimi;
public class MemComputedProperty : TsukimiBehaviour{ private int n;
public int Doubled { get { return n * 2; } }
void Start() { n = 3; Debug.Log(Doubled); // => 6 }}Different accessibility for get and set
Section titled “Different accessibility for get and set”using UnityEngine;using Tsukimi;
public class MbAccessorAcc : TsukimiBehaviour{ void Start() { V = 1; Debug.Log(V); // => 1 }
public int V { get; private set; }}Property initializer
Section titled “Property initializer”using UnityEngine;using Tsukimi;
public class MbAutoPropInit : TsukimiBehaviour{ void Start() { Debug.Log(V); // => 1 }
public int V { get; set; } = 1;}Getter-only auto-property
Section titled “Getter-only auto-property”using UnityEngine;using Tsukimi;
public class MbGetterOnly : TsukimiBehaviour{ void Start() { Debug.Log(V); // => 0 }
public int V { get; }}init accessor
Section titled “init accessor”using UnityEngine;using Tsukimi;
public class MbInitAccessor : TsukimiBehaviour{ void Start() { Debug.Log(V); // => 0 }
public int V { get; init; }}Attribute on the backing field
Section titled “Attribute on the backing field”using UnityEngine;using Tsukimi;
public class MbFieldAttr : TsukimiBehaviour{ void Start() { Debug.Log(V); // => 0 }
[field: SerializeField] public int V { get; set; }}Virtual property
Section titled “Virtual property”A property marked virtual. To override it in a derived type, make the base type abstract.
using UnityEngine;using Tsukimi;
public class MbVirtualProp : TsukimiBehaviour{ void Start() { Debug.Log(V); // => 1 }
public virtual int V { get { return 1; } }}Indexer
Section titled “Indexer”Declaring this[int i] lets you read a value of that type as v[i]. The value written in the brackets arrives as the accessor’s argument.
using UnityEngine;using Tsukimi;
public class MbIndexer : TsukimiBehaviour{ void Start() { Debug.Log(this[2]); // => 20 }
public int this[int i] { get { return i * 10; } }}Writing to an indexer
Section titled “Writing to an indexer”Writing set too lets you write with v[i] = x. The value being written arrives in value, and the index arrives as an argument.
using UnityEngine;using Tsukimi;
public class MbIndexerSet : TsukimiBehaviour{ private int a; private int b;
void Start() { this[0] = 3; this[1] = 4; Debug.Log(this[0] * 10 + this[1]); // => 34 }
public int this[int i] { get { return i == 0 ? a : b; } set { if (i == 0) { a = value; } else { b = value; } } }}Forms that only compile as a declaration
Section titled “Forms that only compile as a declaration”event declaration
Section titled “event declaration”The event declaration compiles. Writing a subscribe or fire line produces TUKI0108.
using UnityEngine;using Tsukimi;
public class MbEventField : TsukimiBehaviour{ void Start() { Debug.Log(1); // => 1 }
public event System.Action Fired;}Writing subscribe/unsubscribe accessors
Section titled “Writing subscribe/unsubscribe accessors”Writing add and remove yourself also compiles, but only as a declaration.
using UnityEngine;using Tsukimi;
public class MbEventAcc : TsukimiBehaviour{ void Start() { Debug.Log(1); // => 1 }
public event System.Action Fired { add { } remove { } }}Forms that compile but do nothing
Section titled “Forms that compile but do nothing”Finalizer
Section titled “Finalizer”The runtime has no mechanism to call finalizers, so the body never runs.
using UnityEngine;using Tsukimi;
public class MbFinalizer : TsukimiBehaviour{ void Start() { Debug.Log(1); // => 1 }
~MbFinalizer() { }}volatile
Section titled “volatile”There is no concurrently running thread of execution, so adding volatile does not change the meaning of reads and writes.
using UnityEngine;using Tsukimi;
public class MbVolatile : TsukimiBehaviour{ void Start() { Debug.Log(V); // => 0 }
private volatile int V;}readonly member of a value type
Section titled “readonly member of a value type”Can be attached to a member that does not modify the value. Value types are copied each time they’re passed, so adding it does not change runtime behaviour.
using UnityEngine;using Tsukimi;
public struct Point { public int X; public readonly int Read() { return X; } }public class MbReadonlyMember : TsukimiBehaviour{ void Start() { Point p = new Point(); Debug.Log(p.Read()); // => 0 }}Overload resolution
Section titled “Overload resolution”Selection by argument count
Section titled “Selection by argument count”using UnityEngine;using Tsukimi;
public class OvByArity : TsukimiBehaviour{ void Start() { Debug.Log(Add(1)); // => 1 Debug.Log(Add(1, 2)); // => 3 }
private int Add(int a) { return a; } private int Add(int a, int b) { return a + b; }}Selection by argument type
Section titled “Selection by argument type”using UnityEngine;using Tsukimi;
public class OvByType : TsukimiBehaviour{ void Start() { Debug.Log(Show(1)); // => 1 Debug.Log(Show("a")); // => 2 }
private int Show(int a) { return 1; } private int Show(string a) { return 2; }}Preference for the candidate with fewer conversions
Section titled “Preference for the candidate with fewer conversions”using UnityEngine;using Tsukimi;
public class OvBetterConv : TsukimiBehaviour{ void Start() { Debug.Log(Show(1)); // => 2 }
private int Show(long a) { return 1; } private int Show(int a) { return 2; }}Expansion into a variable-length argument
Section titled “Expansion into a variable-length argument”using UnityEngine;using Tsukimi;
public class OvExpanded : TsukimiBehaviour{ void Start() { Debug.Log(Sum(1, 2)); // => 2 Debug.Log(Sum(new int[] { 1, 2 })); // => 2 }
private int Sum(params int[] xs) { return xs.Length; }}Preference for the normal candidate
Section titled “Preference for the normal candidate”using UnityEngine;using Tsukimi;
public class OvNormalBeatsParams : TsukimiBehaviour{ void Start() { Debug.Log(Sum(1, 2)); // => 1 }
private int Sum(int a, int b) { return 1; } private int Sum(params int[] xs) { return 2; }}Omitting a default argument
Section titled “Omitting a default argument”using UnityEngine;using Tsukimi;
public class OvDefaultArg : TsukimiBehaviour{ void Start() { Debug.Log(Add(1)); // => 3 Debug.Log(Add(1, 5)); // => 6 }
private int Add(int a, int b = 2) { return a + b; }}Type parameter inference
Section titled “Type parameter inference”Inference from arguments
Section titled “Inference from arguments”using UnityEngine;using Tsukimi;
public class OvInferArgs : TsukimiBehaviour{ void Start() { Debug.Log(Pick(1, 2)); // => 1 }
private T Pick<T>(T a, T b) { return a; }}Inference from array elements
Section titled “Inference from array elements”using UnityEngine;using Tsukimi;
public class OvInferLower : TsukimiBehaviour{ void Start() { Debug.Log(First(new int[] { 1 })); // => 1 }
private T First<T>(T[] xs) { return xs[0]; }}Inference of two type parameters
Section titled “Inference of two type parameters”using UnityEngine;using Tsukimi;
public class OvInferTwo : TsukimiBehaviour{ void Start() { Debug.Log(Left(1, "a")); // => 1 }
private T1 Left<T1, T2>(T1 a, T2 b) { return a; }}Inference from a nested array
Section titled “Inference from a nested array”The element type is also determined from a nested array like T[][].
using UnityEngine;using Tsukimi;
public class OvInferNested : TsukimiBehaviour{ void Start() { Debug.Log(Depth(new int[1][])); // => 1 }
private int Depth<T>(T[][] xs) { return xs.Length; }}Common type from both sides of ?:
Section titled “Common type from both sides of ?:”using UnityEngine;using Tsukimi;
public class OvBestCommon : TsukimiBehaviour{ void Start() { long v = true ? 1 : 2L; Debug.Log(v); // => 1 }}Inheritance and nesting
Section titled “Inheritance and nesting”Nested type
Section titled “Nested type”using UnityEngine;using Tsukimi;
public class MemNestedType : TsukimiBehaviour{ public struct Inner { public int V; }
void Start() { Inner i = new Inner(); Debug.Log(i.V); // => 0 }}Type written in parts
Section titled “Type written in parts”using UnityEngine;using Tsukimi;
public partial class R_part : TsukimiBehaviour{ void Start() { Debug.Log(Helper()); }}
public partial class R_part{ private int extra;
int Helper() { extra = 41; return extra + 1; }}Implementing an abstract method
Section titled “Implementing an abstract method”using UnityEngine;using Tsukimi;
public abstract class MemAbstractBase : TsukimiBehaviour{ public abstract int Get();}
public class MemAbstractLeaf : MemAbstractBase{ public override int Get() { return 1; }
void Start() { Debug.Log(Get()); // => 1 }}Overriding a default implementation
Section titled “Overriding a default implementation”A virtual method can be overridden with override. The base type must be abstract.
using UnityEngine;using Tsukimi;
public abstract class MemVirtualBase : TsukimiBehaviour{ public virtual int Get() { return 0; }}
public class MemVirtualLeaf : MemVirtualBase{ public override int Get() { return 1; }
void Start() { Debug.Log(Get()); // => 1 }}