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

Predefined ValueTuples #1547

Closed
ghost opened this issue May 20, 2018 · 19 comments
Closed

Predefined ValueTuples #1547

ghost opened this issue May 20, 2018 · 19 comments

Comments

@ghost
Copy link

ghost commented May 20, 2018

I'm using this ValueTuple in one of my classes:
(Char from, Char to)
I found that using such tuple many times in code makes it longer and ugly such as:
protected List<(Char from, Char to)> Ranges = new List<(Char from, Char to)>();
Of cource this became a nightmare if the tuple has more than two elements!
but it solves some problems such as this:

public CharClass(params (Char from, Char to)[] ranges){
}

Tuple param array is better that struct param array because it is self descrying and makes calling code shorter:

var x = new CharClass(('a', 'z'), ('A', 'Z'), ('0', '9');

This is better than:
var x = new CharClass(new Range('a', 'z'), new Range('A', 'Z'), new Range ('0', '9');

So, I ask: why can't we declare the ValueTuple as a Type, so we can reuse it anywhere?
Something like this:

ValueTuple CharRange
{
   Char from;
   Char to;
}

So we can write:

protected List <CharRange> Ranges = new List<CharRange>();
public CharClass(params CharRange[] ranges){
}

The param info tool tip should show the CharRange Tuple as (Char from, Char to) so the user knows what he should write. We pass the values to this tuple param as usual:
var x = new CharClass(('a', 'z'), ('A', 'Z'), ('0', '9');

There is another benefit: the names of the elements will not be lost in reflection, because it's now stored in the type declaration.

Note: I think this may relate to Records.
May be this problem can be solved in general be allowing record values to be passed as Tuple syntax (the reverse of the deconstruction).
I know there are plenty of suggestions out there may be similar, but I can't recall them right now.

@HaloFour
Copy link
Contributor

I think they already added this feature in C# 1.0. It's called a struct.

@svick
Copy link
Contributor

svick commented May 20, 2018

So your ValueTuple CharRange is basically a more succinct syntax for the following code?

struct CharRange
{
    public Char From { get; }
    public Char To { get; }
    
    public CharRange(Char from, Char to)
    {
        From = from;
        To = to;
    }
    
    public static implicit operator CharRange((Char from, Char to) tuple)
        => new CharRange(tuple.from, tuple.to);
}

@ghost
Copy link
Author

ghost commented May 20, 2018

@HaloFour @svick

I alredy used this solution:

        protected struct Range<T>
        {
            public T Min;
            public T Max;

            public Range(T min, T max)
            {
                Min = min;
                Max = max;
            }

            public static implicit operator Range<T>((T from, T to) range)
            {
                return new Range<T>(range.from, range.to);
            }

            public static implicit operator (T from, T to) (Range<T> range)
            {
                return (range.Min, range.Max);
            }
        }

But as you can see, I have to make my struct generic type, becuase I need this tow value range of two differnt types. I also use type called CharOrEscape, but practically this makes some problems, espitially when passing a valueTuple array to a List<Range> which needs more code fot casting!
This will be easier and shorter if I just have a predefined ValueTuple!
As I always say : I can work arround any problem, but why should we waste our time in such twisted ways every time, while we can have an esier solution?

@ghost
Copy link
Author

ghost commented May 20, 2018

I replied in the #1546 issue because of the problem of adding an array of type1 to a list of type2. C# can't do the cast even if type1 can be csted to type2!

@HaloFour
Copy link
Contributor

@MohammadHamdyGhanem

The language shouldn't be encouraging developers to tie the code into knots in the manner that you seem to. If you need a named and reusable data structure then you don't need tuples.

@ghost
Copy link
Author

ghost commented May 21, 2018

@HaloFour
I'm working on verbal regex (Verex). I need to make the verbal syntax as clrear, as short and as readable as possible. Passing pairs of values as tuples achives that, but I found my self declaring the same tuples over and over!
Each situations imposes its syntax.
Using a struc will make the verbal longer (adding the new struct part a lot in long expression). Tuples are perfect params for me, but I need s smart sortcut for them!
I konw Tuples were found to give a quick return multiple value, but C# allowed them to be a full type (I made a suggestin before tuples to made a multiple retun value with a suntax similar to annonymous types: {int, string}, and never tought of using that as a parameter!). Tuples are used with collections, and pased as parameters, and appear anywere else! Something like that is powerfull and can get more.

@HaloFour
Copy link
Contributor

@MohammadHamdyGhanem

Each situations imposes its syntax.

You seem to like to invent your syntax as you go along and then propose that C# change to meet what you would like. That's not how this works. It also won't remotely happen on a timescale that makes it relevant to this project that you're working on.

C# is already getting range syntax. Arguing that C# should add a way to name tuples as proper types so that you can use them as a hack of a range syntax is not likely to gain much in the way of traction.

C# already has aliases. You can do using CharRange = System.ValueTuple<char, char>; right now.

@ghost
Copy link
Author

ghost commented May 21, 2018

@HaloFour
This is a sample:

            var x = Pattern.CharClass('a', 'b')
                .AddRanges(('0', '9'), ('j', 'r'))
                .Repeat(5, RepeatMode.Lazy);

This is the best syntax I came up with so far. The pattern will be
[ab0-9j-r]{5}?

@CyrusNajmabadi
Copy link
Member

I'm working on verbal regex (Verex). I need to make the verbal syntax as clrear, as short and as readable as possible.

Don't we already have that? It's a regex :) I thought the point of verex was to not be as short as possible, but instead to encourage a more tree-construction-based approach so you could structurally build your regex programmatically instead of parsing it out of a string.

@CyrusNajmabadi
Copy link
Member

@HaloFour
This is a sample:

            var x = Pattern.CharClass('a', 'b')
                .AddRanges(('0', '9'), ('j', 'r'))
                .Repeat(5, RepeatMode.Lazy);

There is nothing stopping you from taking a Tuple in as your arguments, but then converting it internally to an actual named type. This is trivial to do, and i would not really be very beneficial for the language to provide a shorthand for something that can already be done so simply by you inside your API.

@CyrusNajmabadi
Copy link
Member

This will be easier and shorter if I just have a predefined ValueTuple!

But you have a predefined valuetuple. It already exists and works well. You just don't want to use it :)

As I always say : I can work arround any problem, but why should we waste our time in such twisted ways every time, while we can have an esier solution?

I don't think the proposal makes things easier. You can already do this:

public Pattern AddRanges(params (char, char)[] ranges)
    => AddRanges(ranges.Select(Range.From));

private Pattern AddRanges(IEnumerable<Range<char>> ranges)
{
    // Do whatever you want. with the parameter.
    return this;
}

@ghost
Copy link
Author

ghost commented May 21, 2018

@CyrusNajmabadi
I alredy did the internal conversion between Tuple and Range struct b4 I post this.
What I post here is not a question for a solution (I do this at Stackoverflow, or ask you at gitter :) ). What I post here is my thoughts about C# beeing easier and time saver. I share my thoughts about how the programming language shoud be from my poit of view. This doesn't mean you should agrree on that or share the same vision. These are issues to discuss, mabbe something good come out of one of these discussions somesay.
Note that this is the fifth or sixth definition block I ask for, and all this can be answered by one solution: Give us the ability to define our own code blocks!
thanks.

@BhaaLseN
Copy link

I thought I read this on another issue, but cannot seem to find it. But today, it isn't possible to define tuple aliases:

using System;
// not allowed:
using Person = (string firstName, string lastName);
// works, but has no names to Item1/Item2
using PersonVT = ValueTuple<string, string>;

There's been more than one occasion where I wished to have this to indicate more clearly that I actually mean the same tuple type; and not just one that looks the same.

...or I could just go and define a struct (or class) instead.

@svick
Copy link
Contributor

svick commented May 21, 2018

@BhaaLseN I think you're talking about #423.

@AustinBryan
Copy link

Also, if #100 is added, the current calling code could be such:

// Current:
var x = new CharClass(new Range('a', 'z'), new Range('A', 'Z'), new Range ('0', '9');
// C# 8.0
var x = new CharClass(new('a', 'z'), new('A', 'Z'), new('0', '9');
// Tuples
var x = new CharClass(('a', 'z'), ('A', 'Z'), ('0', '9');

Yes tuples are still the best, but not much better than with #100 to make any significant argument to add it.

@ghost
Copy link
Author

ghost commented Mar 4, 2019

Another approach:
In general, can't we shorten the code by defining a name for reapeated parts like this:
#define CharRange: (Char from, Char to) ?
So, we can write:

protected List <CharRange> Ranges = new List<CharRange>();
public CharClass(params CharRange[] ranges)

@HaloFour
Copy link
Contributor

HaloFour commented Mar 4, 2019

@MohammadHamdyGhanem

#define is used for preprocessor directives, not aliases. You'd use using for aliases, which has already been proposed here: #423

@ghost
Copy link
Author

ghost commented Mar 4, 2019

@HaloFour
I thought of using. but feared you woll say it is for namespaces only, and using static is for static members only! But ofcource I'd prefer using over #def

@HaloFour
Copy link
Contributor

HaloFour commented Mar 4, 2019

@MohammadHamdyGhanem

You can use it for aliases today, it's just somewhat limited. There are various proposals to make it less limited:

using StringDictionary = System.Collections.Generic.Dictionary<string, string>;

@ghost ghost closed this as completed Mar 4, 2019
This issue was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants