Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

docs: Guidance how to write records #2157

Merged
merged 5 commits into from
Mar 7, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
107 changes: 107 additions & 0 deletions doc/Learn/Mvux/Tutorials/HowTo-Records.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
---
uid: Uno.Extensions.Mvux.HowToWriteRecordss
---

# How to write Records with MVUX

## What is a Record

A [record](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/record) behaves like a class, offering the feature of **immutability**, where the values assigned to it remain unchanged once set. It's possible to create records using the `record` modifier, for example:
eriklimakc marked this conversation as resolved.
Show resolved Hide resolved

```csharp
public record MyRecord()
eriklimakc marked this conversation as resolved.
Show resolved Hide resolved
```

Records **can** be, but are not necessarily, immutable.
eriklimakc marked this conversation as resolved.
Show resolved Hide resolved

## Why Immutability in MVUX

Immutability is crucial in MVUX for two main reasons:

### Predictable State Changes

Immutability ensures that once we set a state, it can't be changed. This predictability makes it easier to understand how our application behaves over time. In MVUX, we use immutable data structures to represent the application state.

### Concurrency and Threading

Immutability makes our application more robust in handling concurrency and threading challenges. Immutable data structures are naturally thread-safe, reducing the risk of bugs related to multiple things happening simultaneously in our app.

## How to create immutable records

You can create immutable records in two ways. First, declare your record with a primary constructor and parameters; this will create an immutable record with the specified parameters as its properties:

```csharp
public partial record ChatResponse(string Message, bool IsError);
```

Another way is by creating properties using the `init` keyword instead of `set` to enforce immutability. Here's a brief example:

```csharp
public partial record ChatResponse
{
public string Message { get; init; }
public bool IsError { get; init; }
}
```
eriklimakc marked this conversation as resolved.
Show resolved Hide resolved

When you create a record, if you let the properties change with the `set` keyword, the record won't be immutable. This means you won't be able to lock in or keep the values from changing once you've set them.

## How to use records with MVUX

Records can be instantiated from the presentation layer as a parameter for a request or in the business layer, where data is usually retrieved/processed. For example, in our `ChatService`, we would have the following method being called from the Model. A `ChatEntry` list is received as a parameter from the Model, where `ChatEntry` is also a record, and we create an instance of `ChatResponse`, returning it to the Model:
eriklimakc marked this conversation as resolved.
Show resolved Hide resolved

```csharp
public async ValueTask<ChatResponse> AskAsync(IImmutableList<ChatEntry> history)
{
var request = CreateRequest(history);

var result = await _client.CreateCompletion(request);

if (result.Successful)
{
var response = result.Choices.Select(choice => choice.Message.Content);

return new ChatResponse(string.Join("", responseContent));
}
else
{
return new ChatResponse(result.Error?.Message, IsError: true);
}
}
```

## Updating records

As we are dealing with immutable records, it's not possible to update them or their properties. To achieve that, we need to create a new instance based on the previous record. This ensures we are not modifying data from the UI in the wrong thread. See the example:

eriklimakc marked this conversation as resolved.
Show resolved Hide resolved
Given the `Message` record:

```csharp
public partial record Message(string Content, Status status, Source source);
```

In our Model:

```csharp
...

message = message with
{
Content = response.Message,
Status = response.IsError ? Status.Error : Status.Value
};

//Then you can update your message list displayed in the UI, thread-safe
await Messages.UpdateAsync(message);
...

```

## App Examples

Check out our SimpleCalc workshop and ChatGPT sample to see how we put these tips into action in real apps, using MVUX and immutable records.

- [SimpleCalc Workshop](xref:Workshop.SimpleCalc.GettingStarted)
- [MVUX & XAML](xref:Workshop.SimpleCalc.MVUX.XAML.FirstProject)
- [MVUX & C# Markup](xref:Workshop.SimpleCalc.MVUX.CSharp.FirstProject)
- [ChatGPT Sample](https://github.com/unoplatform/Uno.Samples/tree/master/UI/ChatGPT)
2 changes: 2 additions & 0 deletions doc/Learn/Mvux/toc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
href: xref:Uno.Extensions.Mvux.Overview
- name: "How-To: Get started with Mvux"
href: xref:Uno.Extensions.Mvux.HowToMvuxProject
- name: "How-To: Write Records with MVUX"
href: xref:Uno.Extensions.Mvux.HowToWriteRecords
- name: Feeds
href: xref:Uno.Extensions.Mvux.Feeds
- name: List-Feeds
Expand Down
Loading