# C#: Syntax & Sugar

Source: https://tweens.gd/csharp/syntax-sugar/

No, you’re not seeing things: there’s more than one way to tween a ferret, and that’s fully intentional. While developing tweens.gd, we set out to solve at least two, probably four, problems:

-   Fire onceA one-off that just does its thing.`sprite.TweenPosition(…)`
-   Set values each timeDestinations or timings you want to specify each time.`(to, 0.6, Out.Cubic)`
-   Several targetsThe same motion, applied to several different nodes.`node.Tween(hop)`
-   Small variationsSmall variations for that extra juice.`hop with { Delay = 0.2 }`

Between them, the Structured and Convenient syntaxes cover all four, and both take safe or sweet endpoints.

## Definitions: Structured vs. Convenient

The **Structured** syntax creates a strongly typed, immutable record struct definition to reuse, or to vary with the `with` keyword.

Structured

```csharp
var arrive = new Tweens.Position2D((400, 180), 0.6, Out.Cubic);

sprite.Tween(arrive with { Delay = 0.1 });
```

Fully Structured

```csharp
var arrive = new Tweens.Position2D
{
    To = new (400, 180),
    Duration = 0.6,
    Ease = Out.Cubic,
    Delay = 0.1,
};

sprite.Tween(arrive);
```

The **Convenient** syntax defines and starts a local animation through an extension method, available on a wide variety of nodes and their descendants.

Convenient

```csharp
sprite.TweenPosition((400, 180), 0.6, Out.Cubic, 0.1);
```

A single line is often all you need… until you don’t, which is when the **Structured** syntax comes in super clutch. It’s very useful once your game has a large number of tweens or you want to work on it with multiple devs.

These are alternative ways to start the same motion. Both return a handle when played.

## Values: Safe vs. Sweet

A Godot value states the endpoint’s type; a tuple leaves it out. The compiler checks both, down to the number of components and that each one is a number.

Safe: explicit type or tuple

```csharp
sprite.TweenPosition(new Vector2(400, 180), 0.6);
sprite.TweenPosition((400, 180), 0.6);
```

Arrays are checked when the tween is created: a mismatched length throws `ArgumentException`.

Arrays read closest to GDScript, which is why the array syntax exists.

Sweet: array

```csharp
sprite.TweenPosition([400, 180], 0.6);
```

All three move to the same position, and structured constructors accept the same forms.

| Animate | Shorter endpoint | Checked |
| --- | --- | --- |
| Uniform scale | `sprite.TweenScale(1.2, 0.2)` | By the compiler |
| RGB color | `label.TweenModulate((1, 0.5, 0), 0.3)` | By the compiler |
| Named or HTML color | `label.TweenModulate("tomato", 0.3)` | When the tween is created |

Three color components imply alpha 1. Numeric endpoints need no `f` suffix.

## Easing and delay

Arguments follow **endpoint, duration, ease, delay**. Times are seconds; C# also accepts `TimeSpan`.

An initializer names every setting.

Clean: explicit & readable

```csharp
var arrive = new Tweens.Position2D
{
    To = new Vector2(400, 180),
    Duration = 0.6,
    Ease = Out.Cubic,
    Delay = 0.2,
};
```

Arguments take the same settings in order.

Quick: convenient & concise

```csharp
var arrive = new Tweens.Position2D((400, 180), 0.6, Out.Cubic, 0.2);
sprite.TweenPosition((400, 180), 0.6, Out.Cubic, 0.2);
```

Constructors and convenient calls take the same arguments.

## More options

Set any other option in an initializer, and vary a copy with `with`.

Structured

```csharp
var pulse = new Tweens.Scale2D(1.2, 0.2) { PingPong = true };
sprite.Tween(pulse with { Repeats = 2 });
```

Set any other option in a configure callback, which receives the definition before it starts.

Convenient

```csharp
sprite.TweenScale(1.2, 0.2, options =>
{
    options.PingPong = true;
    options.Repeats = 2;
});
```
