dotnet / dotnet/vblang

Proposal: Extending anonymous types and functions (to complement limitations of Tuples)

Open
#242 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
No language data
Stars
328
Forks
71
PR merge metrics
No merged PRs in 30d

Description

@vbcodec commented on [Sun Sep 11 2016](https://github.com/dotnet/roslyn/issues/13733)

Tuples and corresponding nice tuple's syntax is helpful, but also have serious flaws and limitations.
- not suitable for public API - other languages (including earlier C# and VB) will ignore helpful metadata with names for fields
- not suitable for use with reflection (databinding), because lack of field's names
- misleading behaviour when trying copy values between two different tuples using the same field's names
- locked to ValueTuple type only, no way to extend it (structures are not inheritable)
- lack of working with reference types - different performance characteristics
- require additional library to be shipped together with apps / libraries using tuples

For these cases where Tuples are insufficient, current features can be used, after some easy enhancements:

**1. Inferred return type for functions**

```
Public Function f1
Return 2
End Function
```

Currently inferred return type is Object, what need to be corrected (narrowed) and inferred return type should be Integer (for case above).

Strange, but local functions in VB already have this possibility:

```
Sub s1
Dim lf = Function () 2
Dim lf2 = Function()
Return 3
End Function
End Sub
```

Why other (non-locall) functions don't have this possibility ? There is breaking change or other reasons ? If there is breaking change, then new compiler switch (Option Infer Return [On / Off]) should solve it.

**2. Anonymous types less anonymous**

Inline types with explicit type names

```
Sub s2
Dim lat = New Class C1 With {.Color = "Yellow"}
End Sub
```

which is the same as

```
Class C1
Public Property Color As String
End Class

Sub s2
Dim lat = New C1 With {.Color = "Yellow"}
End Sub
```

This will enable to quickly define type and use it in public API

**3. Anonymous types as structures**

Inline types as structures (also with explicit type names)

```
Sub s3
Dim s = New Structure With {.Color = "Yellow"} ' anonymous structure
Dim s2 = New Structure C2 With {.Color = "Yellow"} ' also with explicit name
End Sub
```

These enhancements will enable to achieve similar results as Tuples while preserving required functionality, where Tuples can't.

---

@gafter commented on [Sun Sep 11 2016](https://github.com/dotnet/roslyn/issues/13733#issuecomment-246209977)

Can you please explain how these would be translated into metadata? How, exactly, would these types be shared across assembly boundaries?

---

@vbcodec commented on [Mon Sep 12 2016](https://github.com/dotnet/roslyn/issues/13733#issuecomment-246338139)

@gafter

There are few possibilities how to generate names for inlined types (anonymous and named)

**Default behaviour**
All named inline types are public and available outside assembly
All anonymous types are private (friend) and available only inside assembly with mangled names

**Customized behaviour using attributes**
Customized generation controlled by InlineTypesGenerationAttribute class with few fields:
- AccessLevel (Boolean) -> True for Public (available outside assembly), False for Private (available only inside assembly)
- Placement (Enumeration) -> Global for global placement (outside any namespace, just like currently anonymous types), CurrentNamespace for placing inside namespace where function is defined, CurrentClass for placing inside current class if function is inside class

For anonymous types available publicly and placed globally or in namespace, mangled name will contain path of namespaces and classes, name of method with "Result" postfix, and eventually numeric identifier for resolve conflicts.

Example:

```

Namespace n1


Public Class c1
Function f1()
Return New With {.A = New With {.B = 0}}
End Function

Function f2()
Dim x = New With {.C = 1}
Return New With {.D = 1}
End Function


Function f3()
Return New With {.E = 1}
End Function
End Class
End Namespace
```

will generate types:

```
Public Class n1_c1_f1Result_1
Public Property A as Integer
End Class

Public Class n1_c1_f1Result_2
Public Property B as Integer
End Class

Friend Class AnonymousType_1
Public Property C as Integer
End Class

Public Class n1_c1_f2Result
Public Property D as Integer
End Class

Public Class c1_f3Result ' placed inside n1 namespace
Public Property E as Integer
End Class
```

This is bit trickery, but clear and give many possibilities to avoid conflict's names and preserve 'humanoid' names as much as possible. Current ValueTuple is also trickery, but fixed and create many limitations.

---

@HaloFour commented on [Mon Sep 12 2016](https://github.com/dotnet/roslyn/issues/13733#issuecomment-246382095)

@vbcodec

The problem is that such generated types are awful to look at and awful to consume. You've not improved the situation at all from tuples. If anything you've made it worse because as public types you've made them incredibly sensitive to breaking changes. The _exact_ mechanism used by the compiler to generate those names then becomes a concrete part of the spec and can _never_ change.

And you still have no assembly boundary compatibility. An anonymous type in one assembly is completely distinct (and incompatible) with an anonymous type in another assembly even if their structure is identical.

As for inference of return types, that would certainly be a breaking change. I also think that it's just a bad idea in general. It hides the contract of the function in a way that can make it incredibly difficult to discern (if not impossible without the compiler helping you), plus there are many scenarios in which the compiler would be required to calculate a lowest common denominator type which, when covering interfaces, would be tricky if not impossible (without CLR-supported intersection types).

I like the idea of extending anonymous types in general, e.g. supporting value-types, implementing interfaces, etc., but I don't think that anonymous types are ever suitable for public consumption. Tuples are slightly more suitable only because their philosophically different; their container type is supposed to be irrelevant, like an argument list. I agree that tuples and public contracts largely shouldn't mix, but I think that anonymous types and public contracts could only be worse.

Contributor guide

No contributing guide indexed for this repository

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.