Vogen icon indicating copy to clipboard operation
Vogen copied to clipboard

Implmement `IFormattable` for `[ValueObject<string>]`

Open aradalvand opened this issue 4 months ago • 4 comments

Describe the bug

It looks like Vogen implements IFormattable by default if the underlying type does; which makes sense. But this is also useful in cases where you have a [ValueObject<string>] — which is obviously "formattable", even if string, the primitive type, technically doesn't implement IFormattable.

I would argue this should even be done by default, or there should at least be an opt-in option to instruct Vogen to implement IFormattable for [ValueObject<string>]s as well, enabling the developer to choose.

Steps to reproduce

This

using Vogen;

Console.WriteLine("Hello, World!");

[ValueObject<string>]
public readonly partial struct Vo;

... generates this:

public readonly partial struct Vo : global::System.IEquatable<Vo>, global::System.IEquatable<System.String>, global::System.IComparable<Vo>, global::System.IComparable, global::System.IParsable<Vo>
{
    // omitted for brevity

Expected behaviour

IFormattable should be implemented, either by default, or via an option. Currently, neither is possible.

aradalvand avatar Aug 16 '25 17:08 aradalvand

Oops! Thanks for reporting @aradalvand - I'll take a look at soon as time permits

SteveDunn avatar Aug 21 '25 11:08 SteveDunn

Hi @aradalvand - I was just taking a look at this. What purpose does the ToString overload have when the underlying is already a string? ToString on the value object just delegates to the ToString on the primitive. The format parameter has no meaning on string, so it's just the format provider. Vogen already implements this for string:

Image
public global::System.String ToString(global::System.IFormatProvider? provider) => IsInitialized() ? Value.ToString(provider) ?? "" : "[UNINITIALIZED]";

SteveDunn avatar Nov 24 '25 22:11 SteveDunn

This is useful when you want to abstract over types that implement IFormattable — imagine, for instance, a T that is constrained to IFormattable because it needs to be printed onto some human-readable medium (e.g. terminal). In that case, Vogen types that have an underlying type of string can't be specified as T even though it does make sense for them to be able to.

I might be missing something so let me know what you think.

aradalvand avatar Nov 24 '25 23:11 aradalvand

@aradalvand - in the situation described, String cannot be passed

Print("Hello world");

static void Print<T>(T t) where T : IFormattable => Console.WriteLine(t.ToString("G", CultureInfo.InvariantCulture));

The type 'string' must be convertible to 'System.IFormattable' in order to use it as parameter 'T' in the generic local function 'void Print<T>(T)

I don't know if I'm missing something (it's usually the case! 😆 )

SteveDunn avatar Nov 25 '25 06:11 SteveDunn