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鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tuple types in using directives #423

Open
gafter opened this Issue Apr 10, 2017 · 44 comments

Comments

@gafter
Member

gafter commented Apr 10, 2017

@gafter commented on Mon Nov 07 2016

It has been requested that we support

using Subject = (bool Gender, double Age);

@HaloFour commented on Mon Nov 07 2016

馃崫 Generic version when combined with #3993?

using Subject<T> = (T Gender, double Age);

@eyalsk commented on Mon Nov 07 2016

That's pretty cool!


@DavidArno commented on Wed Nov 09 2016

At first glance, this seems an excellent idea. But then it takes on the texture of "aerosol cream": it looks like rich, thick, real cream but turns out to be 90% air. Yes, it would be useful occasionally, but the scope would then just be within that file. Some means of giving it a wider scope would really make this useful, eg:

Subject.cs

public global Subject<T> = (T Gender, double Age);

OtherFile.cs

bool GetGender(Subject<bool> subject) => subject.Gender; 

var gender = GetGender((false, 10));

Update
Having thought though this topic, I now feel that @alrz's point re records is pertinent. There should be no need for tuple aliases when we have records. So I no longer think this a useful feature at all.


@dsaf commented on Tue Nov 08 2016

@DavidArno this was previously rejected for some reason #7451.


@DavidArno commented on Tue Nov 08 2016

@dsaf,
That's a shame, but thanks for the link.


@MgSam commented on Tue Nov 08 2016

I'm happy with the proposal as @gafter specified. I think generics and global scope are both orthogonal to this feature and should be considered separately.


@DavidArno commented on Tue Nov 08 2016

Generics and global scope are enhancements to the basic proposal. So you appear to be misusing the term "orthogonal" 馃槢


@MgSam commented on Tue Nov 08 2016

@DavidArno They are completely separable proposals that do not impact the merits of this feature as proposed. I'd call that orthogonal. Scope creep is the death of feature requests.


@qrli commented on Tue Nov 08 2016

I don't see this necessary. It is at best low priority.

If you want a type, define a type.


@alrz commented on Tue Nov 08 2016

Once we have records, it'll be a piece of cake.

struct Subject(bool Gender, double Age);

I'd personally prefer to have generic and global type aliases over this.


@orthoxerox commented on Wed Nov 09 2016

@DavidArno records do not cover all the use cases you might need aliases for. See my example in #7453, there's no way a record can replace a long-winded generic interface type declaration.


@DavidArno commented on Wed Nov 09 2016

@orthoxerox,

Apologies, my comment wasn't clear. I was referring to this specific feature request: tuple aliases, not type aliases in general. I've updated my comment to fix that.


@alrz commented on Wed Nov 09 2016

@DavidArno I'm saying that when you want a named tuple you'd better to define a struct record. But generic and global type aliases are useful for other scenarios, regardless of this proposal.


@AdamSpeight2008 commented on Wed Nov 09 2016

Will the diposable form of using also be supported.

using ( ( MyDisposable0, MyDisposable1 ) )
[
  ...
}

@alrz commented on Sat Nov 12 2016

@AdamSpeight2008 This is already supported:

using (IDisposable d1 = e1, d2 = e2) {}

Also see #9882 and #11420.


@AdamSpeight2008 commented on Sat Nov 12 2016

@alrz That's not what I'm asking.
Let's we have this function.

Function Foo(Of T As IDisposable(Of T), U As IDisposable(Of U)) () As ( T, U )
End Function

And it is call within the header of a using block.

using( Foo() ) { ... }
 // Will both part of the Tuple<T,U> be disposed?

Do the Tuple<T,U> dispose correctly the disposable items within the tuple? eg .Item1 , .Item2


@HaloFour commented on Sat Nov 12 2016

@AdamSpeight2008

#9882


@AdamSpeight2008 commented on Sat Nov 12 2016

@HaloFour If the tuple is decomposed into separate variables, we risk the chance of disposing of a copy.


@HaloFour commented on Sat Nov 12 2016

@AdamSpeight2008

That proposal goes over several potential implementations. Either way, this proposal is about using for aliases, not using for disposables. #9882 is about using for disposables and how that might relate to tuples, if at all.


@jcouv commented on Sat Apr 08 2017

@gafter Should this be moved to csharplang?


@gafter commented on Sun Apr 09 2017

@jcouv yes, I'll move it.

@jnm2

This comment has been minimized.

Show comment
Hide comment
@jnm2

jnm2 Apr 10, 2017

Contributor

I'd like to see using directive aliases for all types, including generic constructions. Tuples would be one particular case of that.

Contributor

jnm2 commented Apr 10, 2017

I'd like to see using directive aliases for all types, including generic constructions. Tuples would be one particular case of that.

@mattwar

This comment has been minimized.

Show comment
Hide comment
@mattwar

mattwar Apr 14, 2017

Global usings sounds like something I would use. I like the generic declaration too.. Let's turn usings into full on type aliases!

mattwar commented Apr 14, 2017

Global usings sounds like something I would use. I like the generic declaration too.. Let's turn usings into full on type aliases!

@jnm2

This comment has been minimized.

Show comment
Hide comment
@jnm2

jnm2 Apr 14, 2017

Contributor

I want two things for two different reasons:

  1. Using directives, only in effect at compile time and no trace of them in the compiled output
  2. Type aliases, in effect at run time, the use of which would enable types to change namespace and name while staying binary compatible.
Contributor

jnm2 commented Apr 14, 2017

I want two things for two different reasons:

  1. Using directives, only in effect at compile time and no trace of them in the compiled output
  2. Type aliases, in effect at run time, the use of which would enable types to change namespace and name while staying binary compatible.
@hardhub

This comment has been minimized.

Show comment
Hide comment
@hardhub

hardhub Apr 23, 2017

Regarding this:
using Subject = (bool Gender, double Age);

Can this be added in something like C# 7.1? I mean it is necessary ASAP.

We can declare tuple like this:
using Subject = ValueTuple<bool, double>;

And work with (bool Gender, double Age) as Subject
But it this case we are loosing names of fields!

Otherwise we will have to use structs as usual... no benefits from new tuples...

hardhub commented Apr 23, 2017

Regarding this:
using Subject = (bool Gender, double Age);

Can this be added in something like C# 7.1? I mean it is necessary ASAP.

We can declare tuple like this:
using Subject = ValueTuple<bool, double>;

And work with (bool Gender, double Age) as Subject
But it this case we are loosing names of fields!

Otherwise we will have to use structs as usual... no benefits from new tuples...

@jnm2

This comment has been minimized.

Show comment
Hide comment
@jnm2

jnm2 Apr 24, 2017

Contributor

I disagree. I'm using tuples over structs to great effect already. Though I am looking forward to using aliases in general, including this.

Contributor

jnm2 commented Apr 24, 2017

I disagree. I'm using tuples over structs to great effect already. Though I am looking forward to using aliases in general, including this.

@hardhub

This comment has been minimized.

Show comment
Hide comment
@hardhub

hardhub Apr 24, 2017

I disagree. I'm using tuples over structs to great effect already. Though I am looking forward to using aliases in general, including this.

If you want to abandon your code clarity it is your choice! But stop propagation of that!

This code de-facto is much less readable without tuples aliases:

if (this.Dictionary.TryGetValue(someuser.Code, out (string Name, string Surname, bool Active) value))
{
}

So I will repeat my question.. Why can we do this?

using Setup = Dictionary<string, (string Name, string Surname, bool Active)>;

But not this?

using Value = (string Name, string Surname, bool Active);
using Setup = Dictionary<string, Value>;

if (this.Dictionary.TryGetValue(someuser.Code, out Value value))
{
}

Or at least this?

using Value = (string Name, string Surname, bool Active);
using Setup = Dictionary<string, (string Name, string Surname, bool Active)>;

if (this.Dictionary.TryGetValue(someuser.Code, out Value value))
{
}

@DavidArno
public global Subject<T> = (T Gender, double Age);

It should NOT be global! It is local alias of type and should be local!

hardhub commented Apr 24, 2017

I disagree. I'm using tuples over structs to great effect already. Though I am looking forward to using aliases in general, including this.

If you want to abandon your code clarity it is your choice! But stop propagation of that!

This code de-facto is much less readable without tuples aliases:

if (this.Dictionary.TryGetValue(someuser.Code, out (string Name, string Surname, bool Active) value))
{
}

So I will repeat my question.. Why can we do this?

using Setup = Dictionary<string, (string Name, string Surname, bool Active)>;

But not this?

using Value = (string Name, string Surname, bool Active);
using Setup = Dictionary<string, Value>;

if (this.Dictionary.TryGetValue(someuser.Code, out Value value))
{
}

Or at least this?

using Value = (string Name, string Surname, bool Active);
using Setup = Dictionary<string, (string Name, string Surname, bool Active)>;

if (this.Dictionary.TryGetValue(someuser.Code, out Value value))
{
}

@DavidArno
public global Subject<T> = (T Gender, double Age);

It should NOT be global! It is local alias of type and should be local!

@DavidArno

This comment has been minimized.

Show comment
Hide comment
@DavidArno

DavidArno Apr 24, 2017

@hardhub,

It's clear you want these local aliases. What's way less clear to me, is what use they'd be. I've never used a type alias and really cannot see how your dictionary example would improve my code. Tuples though have obvious use cases in my view and are the single best feature of C#7.

I'm looking forward to records, but not this alias suggestion.

DavidArno commented Apr 24, 2017

@hardhub,

It's clear you want these local aliases. What's way less clear to me, is what use they'd be. I've never used a type alias and really cannot see how your dictionary example would improve my code. Tuples though have obvious use cases in my view and are the single best feature of C#7.

I'm looking forward to records, but not this alias suggestion.

@hardhub

This comment has been minimized.

Show comment
Hide comment
@hardhub

hardhub Apr 24, 2017

What's way less clear to me, is what use they'd be

As I directly specified above: for code clarity...
Let's say it will be 10 parameters not 3...
Then structs becomes again more and more actual.
I tried new tuples to replace structs in my projects and realized that I cannot get the same clarity without aliases.

cannot see how your dictionary example would improve my code.

It is not about your code it is about my code.. which can look like example provided above...
So does scrolling in GitHub example not make any sense for you?

hardhub commented Apr 24, 2017

What's way less clear to me, is what use they'd be

As I directly specified above: for code clarity...
Let's say it will be 10 parameters not 3...
Then structs becomes again more and more actual.
I tried new tuples to replace structs in my projects and realized that I cannot get the same clarity without aliases.

cannot see how your dictionary example would improve my code.

It is not about your code it is about my code.. which can look like example provided above...
So does scrolling in GitHub example not make any sense for you?

@DavidArno

This comment has been minimized.

Show comment
Hide comment
@DavidArno

DavidArno Apr 24, 2017

As I directly specified above: for code clarity...

If you have 10 parameters, creating an alias would be sticking a plaster over the infected cut. That's not clarity; that's denial. If you have a 10 parameter tuple then it's time to pull up those refactoring tools and get addressing that.

And for your example, I'm not sure you have understood how to use tuples as you appear to be fighting them, rather than working with them. A simple way to do what you are trying to do, is:

class C
{
    private Dictionary<string, (string Name, string Surname, bool Active)> _dictionary = ...

    void M()
    {
        if (_dictionary.TryGetValue("a", out var value))
        {
           // value.Name, value.Surname and value.Active are all in scope here
        }

    ...
}

DavidArno commented Apr 24, 2017

As I directly specified above: for code clarity...

If you have 10 parameters, creating an alias would be sticking a plaster over the infected cut. That's not clarity; that's denial. If you have a 10 parameter tuple then it's time to pull up those refactoring tools and get addressing that.

And for your example, I'm not sure you have understood how to use tuples as you appear to be fighting them, rather than working with them. A simple way to do what you are trying to do, is:

class C
{
    private Dictionary<string, (string Name, string Surname, bool Active)> _dictionary = ...

    void M()
    {
        if (_dictionary.TryGetValue("a", out var value))
        {
           // value.Name, value.Surname and value.Active are all in scope here
        }

    ...
}
@hardhub

This comment has been minimized.

Show comment
Hide comment
@hardhub

hardhub Apr 24, 2017

If you have 10 parameters, creating an alias would be sticking a plaster over the invected cut. That's not >clarity; that's denial. If you have a 10 parameter tuple then it's time to pull up those refactoring tools and >get addressing that.

I do not agree. if we need 10 parameters we still need 10 parameters.. And it should be represented in most clear way available in language for the moment. And tuples without aliases are not the ones. For now it is solved with structs, but it is additional definition which I want to avoid with aliases and new tuples.

private Dictionary<string, (string Name, string Surname, bool Active)> _dictionary =

You will have to specify this tuple everywhere... in each method accepting this value.. or returning this value... in other words in all code related to this tuple or this dictionary. Once again it is question of clarity... Anything complex (massive) is not clear by its definition.

if (dict.TryGetValue("a", out var value))

Nice trick... But...

  1. I prefer solution instead of tricks... Using of tuples aliases is very natural since it is existing for other types.
  2. Using "var" everywhere is evil... it is OK only in cases when it is strongly mandatory.
    We will not discuss that here... you can google different articles why var is not accepted... I can only confirm this fact from point of view of my own experience.

hardhub commented Apr 24, 2017

If you have 10 parameters, creating an alias would be sticking a plaster over the invected cut. That's not >clarity; that's denial. If you have a 10 parameter tuple then it's time to pull up those refactoring tools and >get addressing that.

I do not agree. if we need 10 parameters we still need 10 parameters.. And it should be represented in most clear way available in language for the moment. And tuples without aliases are not the ones. For now it is solved with structs, but it is additional definition which I want to avoid with aliases and new tuples.

private Dictionary<string, (string Name, string Surname, bool Active)> _dictionary =

You will have to specify this tuple everywhere... in each method accepting this value.. or returning this value... in other words in all code related to this tuple or this dictionary. Once again it is question of clarity... Anything complex (massive) is not clear by its definition.

if (dict.TryGetValue("a", out var value))

Nice trick... But...

  1. I prefer solution instead of tricks... Using of tuples aliases is very natural since it is existing for other types.
  2. Using "var" everywhere is evil... it is OK only in cases when it is strongly mandatory.
    We will not discuss that here... you can google different articles why var is not accepted... I can only confirm this fact from point of view of my own experience.
@DavidArno

This comment has been minimized.

Show comment
Hide comment
@DavidArno

DavidArno Apr 24, 2017

Using "var" everywhere is evil...

Ah, I see the problem. What I see as the correct way to use tuples, you see as "tricks". What I see as the best way to write code, you see as "evil". What you see as "clarity", I see as badly written code. Clearly our views are too divergent at a fundamental level for any further meaningful discussion.

DavidArno commented Apr 24, 2017

Using "var" everywhere is evil...

Ah, I see the problem. What I see as the correct way to use tuples, you see as "tricks". What I see as the best way to write code, you see as "evil". What you see as "clarity", I see as badly written code. Clearly our views are too divergent at a fundamental level for any further meaningful discussion.

@DavidArno

This comment has been minimized.

Show comment
Hide comment
@DavidArno

DavidArno Apr 24, 2017

Reading back through this thread is an interesting view on how my take on some ideas changes over time. I started out liking the idea of being able to express something like:

// Subject.cs
global using Subject<T> = (T Gender, double Age);

Then I decided that there was little point to this if we had records. I now find this view reversed: there actually seems little point to records if we can have global aliases like the above.

DavidArno commented Apr 24, 2017

Reading back through this thread is an interesting view on how my take on some ideas changes over time. I started out liking the idea of being able to express something like:

// Subject.cs
global using Subject<T> = (T Gender, double Age);

Then I decided that there was little point to this if we had records. I now find this view reversed: there actually seems little point to records if we can have global aliases like the above.

@GeirGrusom

This comment has been minimized.

Show comment
Hide comment
@GeirGrusom

GeirGrusom Apr 24, 2017

there actually seems little point to records if we can have global aliases like the above.

Metadata. Conversion operators. Interface implementations.

GeirGrusom commented Apr 24, 2017

there actually seems little point to records if we can have global aliases like the above.

Metadata. Conversion operators. Interface implementations.

@hardhub

This comment has been minimized.

Show comment
Hide comment
@hardhub

hardhub Apr 24, 2017

What I see as the correct way to use tuples, you see as "tricks". What I see as the best way to write code, you see as "evil". What you see as "clarity", I see as badly written code.

I do not see any point to treat your opinion as correct.
You ignored absolutely all explanations and just try to say if it is not like I am doing that then all others are idiots.

Just one very simple thing to show your manner of discussion:
I said: Using of tuples aliases is very natural since it is existing for other types.
For me it is argument because it is unified approach for all data types possible in C#.
So why not for tuples? Any your arguments why it should not be this way?

P.S.
Do you think thousands of developers said that var is evil because they are idiots? Or maybe they have some point of view which you cannot simply understand? What is most probable?

hardhub commented Apr 24, 2017

What I see as the correct way to use tuples, you see as "tricks". What I see as the best way to write code, you see as "evil". What you see as "clarity", I see as badly written code.

I do not see any point to treat your opinion as correct.
You ignored absolutely all explanations and just try to say if it is not like I am doing that then all others are idiots.

Just one very simple thing to show your manner of discussion:
I said: Using of tuples aliases is very natural since it is existing for other types.
For me it is argument because it is unified approach for all data types possible in C#.
So why not for tuples? Any your arguments why it should not be this way?

P.S.
Do you think thousands of developers said that var is evil because they are idiots? Or maybe they have some point of view which you cannot simply understand? What is most probable?

@DavidArno

This comment has been minimized.

Show comment
Hide comment
@DavidArno

DavidArno Apr 24, 2017

@GeirGrusom,

Metadata. Conversion operators. Interface implementations.

In my experience, conversion operators are more trouble than they are worth. Why would you want a pure data type to implement an interface? Metadata? Maybe...

DavidArno commented Apr 24, 2017

@GeirGrusom,

Metadata. Conversion operators. Interface implementations.

In my experience, conversion operators are more trouble than they are worth. Why would you want a pure data type to implement an interface? Metadata? Maybe...

@DavidArno

This comment has been minimized.

Show comment
Hide comment
@DavidArno

DavidArno Apr 24, 2017

@hardhub,

You may find it useful to read up on consensus fallacies. Whilst you are at it, it might help to read about false dichotomies too.

DavidArno commented Apr 24, 2017

@hardhub,

You may find it useful to read up on consensus fallacies. Whilst you are at it, it might help to read about false dichotomies too.

@GeirGrusom

This comment has been minimized.

Show comment
Hide comment
@GeirGrusom

GeirGrusom Apr 24, 2017

In my experience, conversion operators are more trouble than they are worth. Why would you want a pure data type to implement an interface? Metadata? Maybe...

Conversion operators can be useful for value types. For example public struct Id<TEntity>(Guid Id) which would allow you a typesafe ID for database items it could be useful to have an explicit cast operator to Guid and vice-versa.

For the interface I guess you could provide an IDeepClone interface, or IWith. It's really difficult to pretend to know every use-case for this, but there definitely are some.

Metadata I think is obvious since ORM objects is an obvious use-case for records.

GeirGrusom commented Apr 24, 2017

In my experience, conversion operators are more trouble than they are worth. Why would you want a pure data type to implement an interface? Metadata? Maybe...

Conversion operators can be useful for value types. For example public struct Id<TEntity>(Guid Id) which would allow you a typesafe ID for database items it could be useful to have an explicit cast operator to Guid and vice-versa.

For the interface I guess you could provide an IDeepClone interface, or IWith. It's really difficult to pretend to know every use-case for this, but there definitely are some.

Metadata I think is obvious since ORM objects is an obvious use-case for records.

@DavidArno

This comment has been minimized.

Show comment
Hide comment
@DavidArno

DavidArno Apr 24, 2017

@GeirGrusom,

Damn, I might have to flip-flop again! 馃榾

DavidArno commented Apr 24, 2017

@GeirGrusom,

Damn, I might have to flip-flop again! 馃榾

@GeirGrusom

This comment has been minimized.

Show comment
Hide comment
@GeirGrusom

GeirGrusom Apr 24, 2017

Speaking of Id<TEntity> there might be a use-case for exporting aliases as well.

public struct Id<TEntity, TId>(TId Value);
using Gid<TEntity> = Id<TEntity, Guid>;
using CustomerId = Id<Customer, long>;

public class Api
{
  public SynergizeCustomerRelation(CustomerId id);

  public CorrelateProfitAgility(Gid<Quarter> quarter);
}

It could be useful to have those type aliases available to API consumers as well.

GeirGrusom commented Apr 24, 2017

Speaking of Id<TEntity> there might be a use-case for exporting aliases as well.

public struct Id<TEntity, TId>(TId Value);
using Gid<TEntity> = Id<TEntity, Guid>;
using CustomerId = Id<Customer, long>;

public class Api
{
  public SynergizeCustomerRelation(CustomerId id);

  public CorrelateProfitAgility(Gid<Quarter> quarter);
}

It could be useful to have those type aliases available to API consumers as well.

@hardhub

This comment has been minimized.

Show comment
Hide comment
@hardhub

hardhub Apr 24, 2017

You may find it useful to read up on consensus fallacies. Whilst you are at it, it might help to read about false dichotomies too.

Exactly what I want to say.. You do not have any arguments even in very simple technical questions. And you try to guard yourself with high-flown words!

Non limitus hominus dolboebus!

hardhub commented Apr 24, 2017

You may find it useful to read up on consensus fallacies. Whilst you are at it, it might help to read about false dichotomies too.

Exactly what I want to say.. You do not have any arguments even in very simple technical questions. And you try to guard yourself with high-flown words!

Non limitus hominus dolboebus!

@DavidArno

This comment has been minimized.

Show comment
Hide comment
@DavidArno

DavidArno Apr 24, 2017

@GeirGrusom,

Nice example that actually shows the benefit of having both records and global type aliases.

This could be achieved using public to denote it's an exported alias:

public struct Id<TEntity, TId>(TId Value);
public using Gid<TEntity> = Id<TEntity, Guid>;
public using CustomerId = Id<Customer, long>;

public class Api
{
  public SynergizeCustomerRelation(CustomerId id);

  public CorrelateProfitAgility(Gid<Quarter> quarter);
}

Could use fairly standard scoping rules:

using Alias = Type; // local to file
private using Alias = Type; // same as above; "private" thus optional as it's the default
internal using Alias = Type; // alias exposed to this project/assembly
public using Alias = Type; // alias exposed to all consumers of this assembly

DavidArno commented Apr 24, 2017

@GeirGrusom,

Nice example that actually shows the benefit of having both records and global type aliases.

This could be achieved using public to denote it's an exported alias:

public struct Id<TEntity, TId>(TId Value);
public using Gid<TEntity> = Id<TEntity, Guid>;
public using CustomerId = Id<Customer, long>;

public class Api
{
  public SynergizeCustomerRelation(CustomerId id);

  public CorrelateProfitAgility(Gid<Quarter> quarter);
}

Could use fairly standard scoping rules:

using Alias = Type; // local to file
private using Alias = Type; // same as above; "private" thus optional as it's the default
internal using Alias = Type; // alias exposed to this project/assembly
public using Alias = Type; // alias exposed to all consumers of this assembly
@HaloFour

This comment has been minimized.

Show comment
Hide comment
@HaloFour

HaloFour Apr 24, 2017

Contributor

Also remember that aliases can't reference other aliases, only fully qualified types. So you wouldn't be able to alias a named tuple and then use that alias as generic type arguments in other aliases. You'd need to submit another proposal to expand those rules, which will likely have to include ways that the compiler can avoid circular references.

Contributor

HaloFour commented Apr 24, 2017

Also remember that aliases can't reference other aliases, only fully qualified types. So you wouldn't be able to alias a named tuple and then use that alias as generic type arguments in other aliases. You'd need to submit another proposal to expand those rules, which will likely have to include ways that the compiler can avoid circular references.

@jnm2

This comment has been minimized.

Show comment
Hide comment
@jnm2

jnm2 Apr 24, 2017

Contributor

@hardhub Using var is a a valid and established practice designed specifically to address this very scenario. For all the years we've used anonymous type projections, we've had no choice but to use var.

Contributor

jnm2 commented Apr 24, 2017

@hardhub Using var is a a valid and established practice designed specifically to address this very scenario. For all the years we've used anonymous type projections, we've had no choice but to use var.

@hardhub

This comment has been minimized.

Show comment
Hide comment
@hardhub

hardhub Apr 24, 2017

@jnm2, anonymous types is single valid usage for var.. for all other cases it is bad practice...
Anonymous types are created during compilation.. for all other cases you know type and it should be used explicitly. But I do not want to discuss it now.. there are lot of information in the internet why it is bad ti use var...

I am just voting to add aliases for tuples as it is now for all other types...

You can do this:
using MyValue = ValueTuple<int, int, int>;

but not this:
using MyValue = (int CustomName1, int CustomName2, int CustomName3);

I think it is ridiculous...

hardhub commented Apr 24, 2017

@jnm2, anonymous types is single valid usage for var.. for all other cases it is bad practice...
Anonymous types are created during compilation.. for all other cases you know type and it should be used explicitly. But I do not want to discuss it now.. there are lot of information in the internet why it is bad ti use var...

I am just voting to add aliases for tuples as it is now for all other types...

You can do this:
using MyValue = ValueTuple<int, int, int>;

but not this:
using MyValue = (int CustomName1, int CustomName2, int CustomName3);

I think it is ridiculous...

@jnm2

This comment has been minimized.

Show comment
Hide comment
@jnm2

jnm2 Apr 24, 2017

Contributor

@hardhub I agree that aliases would be useful. There is plenty of developer consensus on both sides of the var issue. If I had to guess from all my personal interactions and the articles I've read, I'd say var has become the majority position. But each is a valid point of view with plenty of people behind it. I make it a rule to always use var for the same reasons people make it a rule to always use auto in C++. Forced initialization encourages single assignment and a more immutable style of programming. To me var is more readable, maintainable and stylish. But even though I can't relate, I know there are downsides to var for some people too and that's okay.

Contributor

jnm2 commented Apr 24, 2017

@hardhub I agree that aliases would be useful. There is plenty of developer consensus on both sides of the var issue. If I had to guess from all my personal interactions and the articles I've read, I'd say var has become the majority position. But each is a valid point of view with plenty of people behind it. I make it a rule to always use var for the same reasons people make it a rule to always use auto in C++. Forced initialization encourages single assignment and a more immutable style of programming. To me var is more readable, maintainable and stylish. But even though I can't relate, I know there are downsides to var for some people too and that's okay.

@DavidArno

This comment has been minimized.

Show comment
Hide comment
@DavidArno

DavidArno Apr 24, 2017

To me var is more readable, maintainable and stylish

I can't remember which of the language team recently said it, but a good rule of thumb here is:

  1. If most developers will read your code in an IDE, use var. It cuts down noise and improves readability, without reducing discoverability.
  2. If most developers will read your code outside an IDE (eg the BCL code in Github), then avoid var as explicit typing carries more information and improves discoverability.

DavidArno commented Apr 24, 2017

To me var is more readable, maintainable and stylish

I can't remember which of the language team recently said it, but a good rule of thumb here is:

  1. If most developers will read your code in an IDE, use var. It cuts down noise and improves readability, without reducing discoverability.
  2. If most developers will read your code outside an IDE (eg the BCL code in Github), then avoid var as explicit typing carries more information and improves discoverability.
@jnm2

This comment has been minimized.

Show comment
Hide comment
@jnm2

jnm2 Apr 24, 2017

Contributor

See, as to #2, I'd say that to properly understand the returned value's type in context, you'd want to start by look at the method returning it anyway. Once you do that, the type name is right in front of you. 馃槇

(In my experience there are very few times outside the IDE where if the type isn't obvious I don't end up having to look at the method for other reasons too.)

Contributor

jnm2 commented Apr 24, 2017

See, as to #2, I'd say that to properly understand the returned value's type in context, you'd want to start by look at the method returning it anyway. Once you do that, the type name is right in front of you. 馃槇

(In my experience there are very few times outside the IDE where if the type isn't obvious I don't end up having to look at the method for other reasons too.)

@CyrusNajmabadi

This comment has been minimized.

Show comment
Hide comment
@CyrusNajmabadi

CyrusNajmabadi Apr 24, 2017

Geez guys. Just cool it a bit. :) Let's have a nice relaxing discussion about incredibly geeky stuff.

CyrusNajmabadi commented Apr 24, 2017

Geez guys. Just cool it a bit. :) Let's have a nice relaxing discussion about incredibly geeky stuff.

@CyrusNajmabadi

This comment has been minimized.

Show comment
Hide comment
@CyrusNajmabadi

CyrusNajmabadi Apr 24, 2017

My 2c. There are two restrictions going on with aliases that i think we can improve on. The first is that we just generally allow any type syntax to be supplied on the RHS. It seems basically like an overly conservative restriction that the RHS is limited to only named-types. For example, you should be able to also say:

using mdtoken = int;
using StringArray = String[];
using MyLittleTuple = (int friendship, bool isMagic);

Such a system would be trivially easy for us to handle. And i think it would actually just fall out by removing the named-type restriction on the RHS. Prior to tuples this simply wasn't that big an issue. If you wanted to reference a primitive type, you could just use the full-type-name for it. That also applied for Nullable. The only outlier was really arrays, and no one seemed to care. Now that this prevents you from using tuples, the restriction just seems a bit too onerous, and doesn't really seem to be buying us anything.

The second restriction is that an alias is just a simple name, whereas some people want it to be generic. i.e.

using StringMap<T> = Dictionary<string, T>;

This is much more complex as it means that aliases really are more than just a simple-name-to-type-mapping. I think there's value here, but from a language/implementation perspective, it definitely gets more complex.

I would be interested in championing '1', but i think '2' is simply too large and should be broken into other proposals.

Note: while i'm interested in championing, i've also been a terrible champion as i just haven't been able to get the time to work on these things with the enormous amount of other work i've had on my plate as well :-/ So take that as you will...

CyrusNajmabadi commented Apr 24, 2017

My 2c. There are two restrictions going on with aliases that i think we can improve on. The first is that we just generally allow any type syntax to be supplied on the RHS. It seems basically like an overly conservative restriction that the RHS is limited to only named-types. For example, you should be able to also say:

using mdtoken = int;
using StringArray = String[];
using MyLittleTuple = (int friendship, bool isMagic);

Such a system would be trivially easy for us to handle. And i think it would actually just fall out by removing the named-type restriction on the RHS. Prior to tuples this simply wasn't that big an issue. If you wanted to reference a primitive type, you could just use the full-type-name for it. That also applied for Nullable. The only outlier was really arrays, and no one seemed to care. Now that this prevents you from using tuples, the restriction just seems a bit too onerous, and doesn't really seem to be buying us anything.

The second restriction is that an alias is just a simple name, whereas some people want it to be generic. i.e.

using StringMap<T> = Dictionary<string, T>;

This is much more complex as it means that aliases really are more than just a simple-name-to-type-mapping. I think there's value here, but from a language/implementation perspective, it definitely gets more complex.

I would be interested in championing '1', but i think '2' is simply too large and should be broken into other proposals.

Note: while i'm interested in championing, i've also been a terrible champion as i just haven't been able to get the time to work on these things with the enormous amount of other work i've had on my plate as well :-/ So take that as you will...

@HaloFour

This comment has been minimized.

Show comment
Hide comment
@HaloFour

HaloFour Apr 24, 2017

Contributor

@CyrusNajmabadi

It's already #90. Based on Roslyn's #3993 which @gafter preferred to the alternatives.

I think that there's a third proposal buried here too and that's having aliases that refer to other aliases, which is probably even more complicated than either 1 or 2.

Contributor

HaloFour commented Apr 24, 2017

@CyrusNajmabadi

It's already #90. Based on Roslyn's #3993 which @gafter preferred to the alternatives.

I think that there's a third proposal buried here too and that's having aliases that refer to other aliases, which is probably even more complicated than either 1 or 2.

@CyrusNajmabadi

This comment has been minimized.

Show comment
Hide comment
@CyrusNajmabadi

CyrusNajmabadi Apr 24, 2017

I think that there's a third proposal buried here too and that's having aliases that refer to other aliases, which is probably even more complicated than either 1 or 2.

Ah yeah. I would like that as well. We could always implement that as a post pass. i.e. if a typename in an alias it looked up with our current rules, and it fails to find anything, then you can look at the names of previous aliases and bind to those.

That said, again, I think allowing arbitrary type-syntaxes on hte RHS of a normal 'simple name' alias is reasonable, and ideally not that expensive. I would champion it.

CyrusNajmabadi commented Apr 24, 2017

I think that there's a third proposal buried here too and that's having aliases that refer to other aliases, which is probably even more complicated than either 1 or 2.

Ah yeah. I would like that as well. We could always implement that as a post pass. i.e. if a typename in an alias it looked up with our current rules, and it fails to find anything, then you can look at the names of previous aliases and bind to those.

That said, again, I think allowing arbitrary type-syntaxes on hte RHS of a normal 'simple name' alias is reasonable, and ideally not that expensive. I would champion it.

@mattwar

This comment has been minimized.

Show comment
Hide comment
@mattwar

mattwar Apr 24, 2017

I'll champion any proposal that adds more var.

mattwar commented Apr 24, 2017

I'll champion any proposal that adds more var.

@CyrusNajmabadi

This comment has been minimized.

Show comment
Hide comment
@CyrusNajmabadi

CyrusNajmabadi Apr 24, 2017

using Cowbell = var;

CyrusNajmabadi commented Apr 24, 2017

using Cowbell = var;
@DavidArno

This comment has been minimized.

Show comment
Hide comment
@DavidArno

DavidArno Apr 24, 2017

@mattwar,

I'd prefer more let. Perhaps @CyrusNajmabadi could champion the following being valid:

using let = var;

Then I could use let instead of var throughout my code.

馃檲 馃檳 馃檴

Edit: sure Cowbell works for me, too.

DavidArno commented Apr 24, 2017

@mattwar,

I'd prefer more let. Perhaps @CyrusNajmabadi could champion the following being valid:

using let = var;

Then I could use let instead of var throughout my code.

馃檲 馃檳 馃檴

Edit: sure Cowbell works for me, too.

@AdamSpeight2008

This comment has been minimized.

Show comment
Hide comment
@AdamSpeight2008

AdamSpeight2008 Apr 24, 2017

@mattwar and @DavidArno
I'd prefer more dim.

using dim = var;

So it more akin to VB and we all win.

AdamSpeight2008 commented Apr 24, 2017

@mattwar and @DavidArno
I'd prefer more dim.

using dim = var;

So it more akin to VB and we all win.

@IllidanS4

This comment has been minimized.

Show comment
Hide comment
@IllidanS4

IllidanS4 May 5, 2017

using dim = dynamic;

Even more akin to VB. But still, if any type expression after using is to be allowed, this should be too.

IllidanS4 commented May 5, 2017

using dim = dynamic;

Even more akin to VB. But still, if any type expression after using is to be allowed, this should be too.

@TruePluto

This comment has been minimized.

Show comment
Hide comment
@TruePluto

TruePluto Sep 29, 2017

        Dictionary<MyNameIsVeryLong, Lazy<Dictionary<(MyNameIsVeryLong MyNameIsVeryLonga, (MyNameIsVeryLongLong MyNameIsVeryLongab, MyNameIsVeryLongLongLong MyNameIsVeryLongabb)), Lazy<((MyNameIsVeryLong MyNameIsVeryLongaa, (MyNameIsVeryLongLong MyNameIsVeryLongab, MyNameIsVeryLongLongLong MyNameIsVeryLongabb)) Key, (YouNameIsVeryLongToo MyNameIsVeryLongac, (YourNameIsVeryLongToo MyNameIsVeryLongad, HisNameIsVeryLongToo MyNameIsVeryLongae)) Value)>>>> ssssss
            = new Dictionary<MyNameIsVeryLong, Lazy<Dictionary<(MyNameIsVeryLong MyNameIsVeryLonga, (MyNameIsVeryLongLong MyNameIsVeryLongab, MyNameIsVeryLongLongLong MyNameIsVeryLongabb)), Lazy<((MyNameIsVeryLong MyNameIsVeryLongaa, (MyNameIsVeryLongLong MyNameIsVeryLongab, MyNameIsVeryLongLongLong MyNameIsVeryLongabb)) Key, (YouNameIsVeryLongToo MyNameIsVeryLongac, (YourNameIsVeryLongToo MyNameIsVeryLongad, HisNameIsVeryLongToo MyNameIsVeryLongae)) Value)>>>>();

that will be ok

TruePluto commented Sep 29, 2017

        Dictionary<MyNameIsVeryLong, Lazy<Dictionary<(MyNameIsVeryLong MyNameIsVeryLonga, (MyNameIsVeryLongLong MyNameIsVeryLongab, MyNameIsVeryLongLongLong MyNameIsVeryLongabb)), Lazy<((MyNameIsVeryLong MyNameIsVeryLongaa, (MyNameIsVeryLongLong MyNameIsVeryLongab, MyNameIsVeryLongLongLong MyNameIsVeryLongabb)) Key, (YouNameIsVeryLongToo MyNameIsVeryLongac, (YourNameIsVeryLongToo MyNameIsVeryLongad, HisNameIsVeryLongToo MyNameIsVeryLongae)) Value)>>>> ssssss
            = new Dictionary<MyNameIsVeryLong, Lazy<Dictionary<(MyNameIsVeryLong MyNameIsVeryLonga, (MyNameIsVeryLongLong MyNameIsVeryLongab, MyNameIsVeryLongLongLong MyNameIsVeryLongabb)), Lazy<((MyNameIsVeryLong MyNameIsVeryLongaa, (MyNameIsVeryLongLong MyNameIsVeryLongab, MyNameIsVeryLongLongLong MyNameIsVeryLongabb)) Key, (YouNameIsVeryLongToo MyNameIsVeryLongac, (YourNameIsVeryLongToo MyNameIsVeryLongad, HisNameIsVeryLongToo MyNameIsVeryLongae)) Value)>>>>();

that will be ok

@Thaina

This comment has been minimized.

Show comment
Hide comment
@Thaina

Thaina Dec 29, 2017

This would be really great feature

Thaina commented Dec 29, 2017

This would be really great feature

@madelson

This comment has been minimized.

Show comment
Hide comment
@madelson

madelson May 9, 2018

I'd be in favor of supporting the basic version of this:

using MyName = (int a, string b...);

While this would be a new feature, conceptually it feels more like it removes a caveat in how two existing features work together. The language becomes easier to learn and understand when there are fewer caveats like this.

Other pieces of this proposal (such as adding the global option) feel more like brand new things and don't feel all that compelling to me.

madelson commented May 9, 2018

I'd be in favor of supporting the basic version of this:

using MyName = (int a, string b...);

While this would be a new feature, conceptually it feels more like it removes a caveat in how two existing features work together. The language becomes easier to learn and understand when there are fewer caveats like this.

Other pieces of this proposal (such as adding the global option) feel more like brand new things and don't feel all that compelling to me.

@AustinBryan

This comment has been minimized.

Show comment
Hide comment
@AustinBryan

AustinBryan Jun 8, 2018

I think global aliases are a great idea. I've had to reuse an alias before in multiple files and it's annoying to have to keep typing or copy and pasting. Plus, then we'd only have to change the alias value in one place, instead of 20.

AustinBryan commented Jun 8, 2018

I think global aliases are a great idea. I've had to reuse an alias before in multiple files and it's annoying to have to keep typing or copy and pasting. Plus, then we'd only have to change the alias value in one place, instead of 20.

@weitzhandler

This comment has been minimized.

Show comment
Hide comment
@weitzhandler

weitzhandler Oct 17, 2018

Very compelling, because when using ValueTuple as an alias you can't name the various field.

Please implement this feature!

weitzhandler commented Oct 17, 2018

Very compelling, because when using ValueTuple as an alias you can't name the various field.

Please implement this feature!

@Thaina

This comment has been minimized.

Show comment
Hide comment
@Thaina

Thaina Oct 18, 2018

Somehow I think global alias is better be normal plain old struct

Thaina commented Oct 18, 2018

Somehow I think global alias is better be normal plain old struct

@weitzhandler

This comment has been minimized.

Show comment
Hide comment
@weitzhandler

weitzhandler Oct 18, 2018

I think global is out of this issues scope. Although global might be a good idea in general, I see the current suggestion of addressing C# value type using aliases more important to me.

weitzhandler commented Oct 18, 2018

I think global is out of this issues scope. Although global might be a good idea in general, I see the current suggestion of addressing C# value type using aliases more important to me.

@Thaina

This comment has been minimized.

Show comment
Hide comment
@Thaina

Thaina Oct 18, 2018

@weitzhandler I don't think so. If you need to have alias for tuple more than one file it suspiciously should be solid class or struct

Thaina commented Oct 18, 2018

@weitzhandler I don't think so. If you need to have alias for tuple more than one file it suspiciously should be solid class or struct

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment