Giter Site home page Giter Site logo

Comments (69)

gafter avatar gafter commented on August 26, 2024 122

We have no expectation of ever doing anything like this.

from roslyn.

Porges avatar Porges commented on August 26, 2024 21

Just noticed this in Don Syme’s History of F# paper for HOPL 😁

Surprisingly this feature is yet to make it into any version of C#.

from roslyn.

MadsTorgersen avatar MadsTorgersen commented on August 26, 2024 20

This proposal seems related to object expressions in F# or anonymous inner classes in Java, both of which let you specify class implementations right when you new the objects up.

You could certainly imagine an evolution of anonymous objects in C# that would combine the current behavior with the ability to inherit classes, implement interfaces and supply member implementations.

from roslyn.

Porges avatar Porges commented on August 26, 2024 14

That's disappointing.

Here's an example that came up today. Let's say we have some interface IParseMessages:

interface IParseMessages
{
    bool Parse(IMessage message);
}

Now we want to be able to add other stages to the parsing pipeline (think something like the handlers in ASP.NET), which can decide whether or not to invoke the "base" message parser. None of these handlers know anything about each other (we can't just link them all together when we write them). We could have a type like this:

public interface IMessageHandler
{
    bool Parse(IMessage message, Func<IMessage, bool> inner);
}

The IMessageHandler can now check the message and then decide whether or not to call onto the inner handler.

Something that would be useful here would be to be able to fuse two message handlers together to form a new handler:

public static class MessageHandlerExtensions
{
    public static IMessageHandler Then(this IMessageHandler derived, IMessageHandler baseImpl)
        => new ComposedMessageHandler(derived, baseImpl);

    private sealed class ComposedMessageHandler : IMessageHandler
    {
        private readonly IMessageHandler _derived;
        private readonly IMessageHandler _baseImpl;

        public ComposedMessageHandler(IMessageHandler derived, IMessageHandler baseImpl)
        {
            _derived = derived;
            _baseImpl = baseImpl;
        }

        public bool Parse(IMessage message, Func<IMessage, bool> inner)
            => _derived.Parse(message, msg => _baseImpl.Parse(msg, inner));
    }
}

Now, if we have a list of IMessageHandlers we can combine them all with something like (depending on what order you want them applied) handlers.Aggregate((d, b) => b.Then(d)). (AKA, IMessageHandlers are monoidal).

You might notice that that's a lot of typing. It would be nice to be able to write this instead, replacing all the code in the last block (using my proposed syntax):

public static class MessageHandlerExtensions
{
    public static IMessageHandler Then(this IMessageHandler derived, IMessageHandler baseImpl)
        => new IMessageHandler with {
           bool Parse(IMessage message, Func<IMessage, bool> inner)
               => derived.Parse(message, msg => baseImpl.Parse(msg, inner));
        };
}

Aside: compare the F# which would be something like:

let combine (derived : IMessageHandler) (baseImpl : IMessageHandler) =
    { new IMessageHandler with
        member __.Parse msg inner =
            derived.Parse msg (fun m -> baseImpl.Parse m inner) }

Finally, we then need a way to augment an IParseMessages with the combined IMessageHandler, to produce a new fused IParseMessages that we can pass around. In current C# this could be something like:

public static class MessageParserExtensions
{
    public static IParseMessages Augment(this IParseMessages me, IMessageHandler handler)
        => new AugmentedMessageParser(handler, me);
}

sealed class AugmentedMessageParser : IParseMessages
{
    private readonly IMessageHandler _handler;
    private readonly IParseMessages _impl;

    public AugmentedMessageParser(IMessageHandler handler, IParseMessages impl)
    {
        _handler = handler;
        _impl = impl;
    }

    public bool Parse(IMessage message) => _handler.Parse(message, _impl.Parse);
}

Using the proposed syntax this could be reduced to the much smaller:

public static class MessageParserExtensions
{
    public static IParseMessages Augment(this IParseMessages me, IMessageHandler handler)
        => new IParseMessages with { 
            bool Parse(IMessage message) => handler.Parse(message, me.Parse); };
}

Again, to compare with F# this would be:

let augment (me : IParseMessages) (handler : IMessageHandler) =
    { new IParseMessages with
        member __.Parse msg = handler.Parse msg me.Parse}

I think this reduction in boilerplate would be very useful.

from roslyn.

Richiban avatar Richiban commented on August 26, 2024 12

I've literally wanted this feature for years... If it worked then say goodbye to fakes, mocks and generated decorators!

This might give new lease of life to anonymous types since, as far as I can tell, they're about to be completely superseded by tuples. Giving them the ability to implement interfaces would give them a reason to continue existing.

from roslyn.

gafter avatar gafter commented on August 26, 2024 11

I don’t know what you may be missing, but I believe that local class declarations give you the full power in a much more readable and clear form.

from roslyn.

HaloFour avatar HaloFour commented on August 26, 2024 9

@gafter

Are there public APIs in Java that have anonymous types?

No, there are public APIs throughout Java and the Java ecosystem that expose interfaces for use as callbacks, and the idiomatic (and natural) approach to implementing them is via anonymous types.

https://github.com/google/guava/wiki/FunctionalExplained
https://hc.apache.org/httpcomponents-asyncclient-ga/quickstart.html
https://commons.apache.org/proper/commons-functor/examples.html
https://github.com/Netflix/Hystrix/wiki/How-To-Use#Reactive-Execution
http://reactivex.io/documentation/operators/filter.html
https://developer.android.com/guide/topics/ui/ui-events
https://developer.android.com/guide/topics/location/strategies
https://docs.oracle.com/javafx/2/events/handlers.htm
https://docs.oracle.com/javase/7/docs/api/java/beans/EventHandler.html
http://netty.io/wiki/user-guide-for-4.x.html#wiki-h3-9
https://jersey.github.io/documentation/latest/rx-client.html
https://github.com/AsyncHttpClient/async-http-client#using-custom-asynchandlers

I honestly think you'd find it pretty difficult to find API docs that would suggest implementing callback interfaces using local types over anonymous types.

from roslyn.

Spongman avatar Spongman commented on August 26, 2024 8

very disappointed that this was closed without reason.

from roslyn.

HaloFour avatar HaloFour commented on August 26, 2024 7

@gafter

I don’t know what you may be missing, but I believe that local class declarations give you the full power in a much more readable and clear form.

But with unnecessary boilerplate, even by Java standards. In my experience local type declarations are nearly non-existent in the Java ecosystem, but anonymous classes are exceptionally common. This was especially true leading up to Java finally getting lambdas. If you look at any of the helper packages for Java that deal in functional concepts or callbacks they all use anonymous types, including those from Google, Netflix, Apache, Amazon, etc., both internally and in any example they provide for using their APIs.

I could probably count the number of times I've seen local declarations in the wild on one hand, at best. The only times I've ever reached for them myself was to emulate closures in lambdas due to Java forcing all enclosed locals to be effectively final. With Java 10 that's no longer necessary and I will refactor all of that code to using anonymous classes instead.

public IDisposable Foo() {
    class Foo : IDisposable {
        public void Dispose() {
            Console.WriteLine("Disposed!");
        }
    };
    return new Foo();
}

vs.

public IDisposable Foo() => new IDisposable {
    void Dispose() => Console.WriteLine("Disposed!");
};

There's nothing unreadable about that second example. If anything I think it does a much better job of focusing on what it actually does.

from roslyn.

crystalcodesoftware avatar crystalcodesoftware commented on August 26, 2024 6

We have no expectation of ever doing anything like this.

Well, boo to you.

from roslyn.

HaloFour avatar HaloFour commented on August 26, 2024 6

@gafter

Furthermore, if Java/Android interop is given as one of the reasons for adopting default interface members (of which I am in favor, regardless of the justification), then I can state that the same interop is a good reason to adopt anonymous classes.

As @errorx666 stated, Android dev is interface-driven for callbacks. This makes them cumbersome to use from C# as you have to declare an entire separate class. Local types help, but that's still a lot of ceremony to declare and instantiate to effectively emulate what would be an exceptionally verbose lambda. To improve that situation from C# I would recommend that anonymous types are considered. Even better would be to allow lambda syntax with interfaces with exactly one required method (or also expand that out to abstract types, like Scala supports). Incidentally, poking at the Android docs, they clearly favor anonymous classes also.

from roslyn.

rashadrivera avatar rashadrivera commented on August 26, 2024 6

t00 proposed:

interface IPerson
{
    string Name { get; }
    bool IsDeceased { get; }
}

interface IEmployee
{
    string Boss { get; }
}

IPerson GetPerson()
{
    return new : IPerson, IEmployee
    {
        Name = "John",
        IsDeceased = true,
        Boss = "OK",
        ExtraProperty = 123
    };
}

Sorry, but the syntax just seem wrong for the C# language. It's to laxed like JavaScript is and takes away from the strong-typing we've come to expect. While I believe C# could benefit from adding scaffolding to anonymous types (albeit via interfaces or other), I don't think this proposed code example is the way to go about it.

from roslyn.

 avatar commented on August 26, 2024 5

I've been working with Xamarin for Android recently, and because the underlying API is Java based, you're generally expected to pass in an interface implementation where typical C# conventions would use delegates or lambdas.
In Java this is simple: use an anonymous class. In C#, you end up creating multiple unnecessary classes and it's very cumbersome.

from roslyn.

Spongman avatar Spongman commented on August 26, 2024 5

@rashadrivera there's no weak-typing used in that example. the example uses syntax similar to Object Initializers introduced in C# 3.0. Have you updated to C# 3.0 yet?

from roslyn.

aluanhaddad avatar aluanhaddad commented on August 26, 2024 4

I am skeptical of the property implementation syntax, I think it should be something like

return new : IPerson, IEmployee
{
    Name => "John",
    IsDeceased => true,
    Boss => "OK",
    ExtraProperty => 123
};

or

return new : IPerson, IEmployee
{
    Name { get; } = "John",
    IsDeceased { get; } = true,
    Boss { get; } = "OK",
    ExtraProperty { get; } = 123
};

because we are defining a type that implements the properties of the interfaces, where as in the case of anonymous types, the compiler is generating a type definition for us based on the names and values of the instantiation expression.

from roslyn.

gafter avatar gafter commented on August 26, 2024 4

Local type declarations are still on the table.

The most value I ever got from anonymous types in Java was a series of counterintuitive examples for the book Java Puzzlers.

from roslyn.

mattwar avatar mattwar commented on August 26, 2024 3

The reason anonymous types are not passable outside the scope where they are created is due to a lack of unification of types across assemblies in the runtime, not a design philosophy. Giving anonymous types an interface is a good idea. I believe it was proposed during the design for anonymous types but was outside the intent of the feature at the time.

from roslyn.

t00 avatar t00 commented on August 26, 2024 3

As anonymous classes are created with only getters available and only in the current scope this feature might be non-trivial to implement.

But implementation can happen in 2 stages, 1 for getter-only interfaces and 2 for getter and setter + methods.

I would say implementing only interfaces containing property getters would be a huge improvement and should not change anonymous constructor code apart from adding inheritance to the anonymous class.

Inheritance syntax should be explicit and any setter or method on the interface or missing property on the anonymous implementation should trigger an error:

interface IPerson
{
    string Name { get; }
    bool IsDeceased { get; }
}

interface IEmployee
{
    string Boss { get; }
}

IPerson GetPerson()
{
    return new : IPerson, IEmployee
    {
        Name = "John",
        IsDeceased = true,
        Boss = "OK",
        ExtraProperty = 123
    };
}

from roslyn.

Spacefish avatar Spacefish commented on August 26, 2024 3

This would be great to implement multiple action callbacks.. Image a class which downloads a file:
Callback Interface:

public interface IDownloadResultHandler {
    void Success(string path);
    void Fail();
}

Class:

public class FileDownloader {
  public static void Download(string path, IDownloadResultHandler callback) {
    // starts download on a second thread and returns but keeps handle to callback
    ....
  }
  internal static void downloadThread() {
   ...
   if(success) {
     this.callback.Success(pathOfFile);
   }
   else {
      this.callback.Fail();
    }
  }
}

Later on this could be used like this

MyConsole console = new MyConsole();
FileDownloader.Download("/path/to/file", new : IDownloadResultHandler {
    Success() { console.Write("Success"); }
    Fail() { console.Write("Failed.."); }
});

Currently one has to implement a seperate class which implements the interface and pass the environment via a constructor parameter or inject it via dependency injection..

Having anonymous Implementations of interfaces could save us from a lot of boilerplate code.. Furthermore "Callbacks" could explicitly state if they support a different functionality by implementing a interface or not!

from roslyn.

Porges avatar Porges commented on August 26, 2024 3

I'm going to post another example just 'cause.

Here's some C#:

public Sink<TIn, TResult2> MapResult<TResult2>(Func<TResult, TResult2> projection)
    => new MappedResult<TResult2>(this, projection);

private sealed class MappedResult<TResult2> : Sink<TIn, TResult2>
{
    private Sink<TIn, TResult> _sink;
    private Func<TResult, TResult2> _projection;

    public MappedResult(Sink<TIn, TResult> sink, Func<TResult, TResult2> projection)
    {
        _sink = sink;
        _projection = projection;
    }

    public override ActiveSink<TIn, TResult2> Open() => new Impl(_sink, _projection);

    private sealed class Impl : ActiveSink<TIn, TResult2>
    {
        private ActiveSink<TIn, TResult> _sink;
        private Func<TResult, TResult2> _projection;

        public Impl(Sink<TIn, TResult> sink, Func<TResult, TResult2> projection)
        {
            _sink = sink.Open();
            _projection = projection;
        }

        public override TResult2 Result => _projection(_sink.Result);

        public override void Dispose() => _sink.Dispose();

        public override Task ProcessChunk(ReadOnlySpan<TIn> span, CancellationToken cancellationToken)
            => _sink.ProcessChunk(span, cancellationToken);
    }
}

Here's the exact same thing using object expressions in F#:

member me.MapResult (projection : 'TResult -> 'TResult2) : Sink<'T, 'TResult2> =
    { new Sink<'T, 'TResult2>() with
      override __.Open() = 
        let activeSink = me.Open() in
        { new ActiveSink<'T, 'TResult2> with
          override __.Dispose() = activeSink.Dispose()
          override __.ProcessChunk c ct = activeSink.ProcessChunk c ct
          override __.Result with get() = projection activeSink.Result
        }
    }

Being able to close over variables in anonymous type definitions cuts down on a lot of boilerplate.

By comparison, here is the equivalent Java (with anonymous classes):

  public <TResult2> Sink<TIn, TResult2> MapResult(Function<TResult, TResult2> f)
  {
    Sink<TIn, TResult> me = this;
    return new Sink<TIn, TResult2>() {
      public ActiveSink<TIn, TResult2> open() {
        ActiveSink<TIn, TResult> activeSink = me.open();
        return new ActiveSink<TIn, TResult2>() {
          public TResult2 result() { return f.apply(activeSink.result()); }
          public void close() { activeSink.close(); }
          public void processChunk(TIn[] c) { activeSink.processChunk(c); }
        };
      }
    };
  }

And here's a hypothetical "C# with anonymous classes/object expressions":

public Sink<TIn, TResult2> MapResult<TResult2>(Func<TResult, TResult2> f)
{
    var me = this;
    return new Sink<TIn, TResult2> with {
        override ActiveSink<TIn, TResult2> Open() {
            var activeSink = me.Open();
            return new ActiveSink<TIn, TResult2> with {
                override TResult2 Result => f(activeSink.Result);
                override void Dispose() => activeSink.Dispose();
                override Task ProcessChunk(TIn[] c, CancellationToken ct)
                    => activeSink.ProcessChunk(c, ct);
            };
        }
    };
}

from roslyn.

BrianBu01 avatar BrianBu01 commented on August 26, 2024 3

Is it time to revisit this now that Record/Data construct solves most of the mention concerns?

Maybe this idea wasn't right for class interfaces, but it is for Record/Data interfaces.

from roslyn.

gafter avatar gafter commented on August 26, 2024 1

Note that records (#206) can implement interfaces. I think that satisfies the underlying need of this request.

from roslyn.

dsaf avatar dsaf commented on August 26, 2024 1

@gafter Can records be declared within method body? I think this request is about not polluting the namespaces and creating explicit named types, rather than creating immutable classes with compact syntax. I believe these are different.

from roslyn.

jcdickinson avatar jcdickinson commented on August 26, 2024 1

@alrz +1. Just use a comma for consistency. Isn't the return type+visibility redundant (unless internal interfaces make an appearance)?

return new ICustomer {
  Name = "Jim",
  Surname = "Bob",
  IsValid() => true,
  Foo = bar,
  Baz() => false
};

from roslyn.

jnm2 avatar jnm2 commented on August 26, 2024 1

I have never written Java, so am I missing something? I still really want this for C#.

from roslyn.

jnm2 avatar jnm2 commented on August 26, 2024 1

@jbtibor dotnet/csharplang#130

from roslyn.

Spacefish avatar Spacefish commented on August 26, 2024 1

@jnm2 that´s not really the same thing.. anonymous types implementing an interface would allow you to pass them as a reference to multiple callbacks to a long running action / task.. Such a pattern is heavily used in Android in Java..
There are typically multiple things that could happen if you trigger some asynchronous actions.. If you only have one callback/delegate you have to have multiple parameters which are not used in all cases, passing an object which implements functions for that cases looks much cleaner / is more readable.

from roslyn.

gafter avatar gafter commented on August 26, 2024 1

that the same interop is a good reason to adopt anonymous classes.

Are there public APIs in Java that have anonymous types?

from roslyn.

Spongman avatar Spongman commented on August 26, 2024 1

Feature requests for C# can be opened in https://github.com/dotnet/csharplang

sounds like that would just be a waste of time:

We have no expectation of ever doing anything like this.

from roslyn.

HaloFour avatar HaloFour commented on August 26, 2024 1

There is:

dotnet/csharplang#2517
dotnet/csharplang#2298

from roslyn.

vbjay avatar vbjay commented on August 26, 2024 1

Being able to do something like

using (var itm = new {Name = "Jay"})
{
	//Do stuff with itm knowing itm.Name would be disposed and any other IDIsposable properties in itm.  
}

would be useful.

from roslyn.

nemec avatar nemec commented on August 26, 2024

I like the idea. Although anonymous types aren't meant to be passed outside the scope where they're created, interfaces are all about the contract so it doesn't matter much that the implementation is compiler-generated.

Per your suggestion about methods, it looks like C# 6 already blurs the line between methods and delegates (from a syntax standpoint), so maybe it's not such a far-fetched suggestion.

from roslyn.

nvivo avatar nvivo commented on August 26, 2024

Thinking out loud here, it seems that I could break my proposal in two:

  1. Allow anonymous objects to include methods and writeable properties.
  2. Allow anonymous objects to implement interfaces

Once the first is achieved, the second one should be straightforward.

To me, it is clear the idea is very useful and would reduce drastically the number "dumb" classes I need just to return models in interface driven code.

But it raises some questions:

  • How to declare a writeable property in an anonymous object?
  • If the property is writeable, does it require an initial value?
new {
    // new modifier keyword?
    readwrite Name = "foo",  
    readwrite string Name,

    // no types, always infer from the value?
    readwrite Name = default(string),

    // no value implies it will be set later, hence writeable? - looks strange
    string Name;

    // borrow syntax from real properties?
    string Name { get; set; },
    Name { get; set; } = "initial value",

    // or imply the get and require only the set?
    string Name { set; },
    Name { set; } = "initial value",
}
  • And If I know beforehand the declaration type, could it infer the interface?
interface IPerson {
    string Name { get; set; }
    bool IsDeceased { get; set; }
}

IPerson GetPerson() {
    return new {
        Name = "John"
    };
}

This would create some form of "duck typing", making like implementing one-time used interfaces easier.

interface ISystemClock {
    DateTimeOffset Now()
} 

iocContainer.Resolve<ISystemClock>().With(new { Now() => DateTimeOffset.Now });

from roslyn.

Porges avatar Porges commented on August 26, 2024

I duped this (as linked above), with an alternative syntax.

from roslyn.

iSynaptic avatar iSynaptic commented on August 26, 2024

+1

from roslyn.

aluanhaddad avatar aluanhaddad commented on August 26, 2024

+1

from roslyn.

dsaf avatar dsaf commented on August 26, 2024

+1

@nvivo Are you requesting specifically interface implementations or subtyping as well?

Depending on that #1728 might be a duplicate.

Also what do you mean by saying "interface driven design"?

Relevant quote:

http://www.jot.fm/issues/issue_2005_07/article1.pdf

Note that as generalizations, interfaces compete with abstract classes. In fact, in
practice interfaces and abstract classes are sometimes used as if they were the same
concept. However, since abstract classes have the potential to pass on implementation to
their subclasses, they should be used if (and only if) the relationship to the subclasses is
genetic, i.e., if it is (or at least could be) based on the inheritance of internal structure, that
is, implementation. If on the other hand the relationship is based on pure function (or,
weaker still, on sameness of protocol), interfaces should be used. For instance, a linked
list and a dynamic array would normally not be genetically related (i.e., have no common
pieces of implementation), yet they share the interface of lists (specifying sequential
access to their elements).

from roslyn.

jbtibor avatar jbtibor commented on August 26, 2024

+1

from roslyn.

jcdickinson avatar jcdickinson commented on August 26, 2024

+1

Also thinking out loud here.

Concern 1

What about methods? One thing I've done for mock objects (without a mocking framework) in the past is to store a delegate that has the matching signature in a private field and invoke that from the interface. E.g.

interface ICustomer {
  string Name { get; }
  string Surname { get; }
  bool IsValid();
}

return new ICustomer() {
  Name = "Jim",
  Surname = "Bob",
  IsValid = () => true
};

This would roughly compile to:

class ICustomerAnyonymousType {
  public string Name { get; set; }
  public string Surname { get; set; }
  public Func<bool> IsValidImplementation { get; set; } // Or a private field
  public bool IsValid() {
    var impl = IsValidImplementation;
    if (impl == null) throw new NotImplementedException(); 
    return impl(); 
  }
}

return new ICustomerAnyonymousType() {
  Name = "Jim",
  Surname = "Bob",
  IsValidImplementation = () => true
};

Concern 2

What about default values? I might not want to provide an implementation for a method or omit a property. Possibly:

return new default ICustomer() {
  Name = "Jim"
};

Surname would return null, and IsValidImplementation would be set to null (causing a NotImplementedException). If default is omitted all members must be provided (else there will be compile failure).

Why?

Unit tests and mocking. For trivial scenarios (not involving abstract or sealed classes) you could mock your objects as follows:

[Fact]
public void DisplayCustomer_ValidateCalled()
{
    var validateCalled = false;
    var customer = new ICustomer() {
      Name = "Jim",
      Surname = "Bob",
      IsValid = () => validateCalled = true
    }
    sut.Display(customer);
    Assert.True(validateCalled);
}

[Fact]
public void DeleteCustomer_Deleted()
{
    var customer = new default ICustomer() {
      Name = "Jim",
      Surname = "Bob"
      // Omit IsValid because it is never called.
      // NotImplementedException would be thrown if it was
      // somehow called.
    }
    sut.Deleted(customer);
    Assert.Null(sut.GetCustomer(customer));
}

from roslyn.

alrz avatar alrz commented on August 26, 2024

@jcdickinson

return new ICustomer() {
  Name = "Jim",
  Surname = "Bob",
  IsValid = () => true
};

It's not clear that you're initializing a property of type Func<bool> or implementing the method. I think this should be done in a more explicit way like:

return new ICustomer {
  public string Name => "Jim";
  public string Surname => "Bob";
  public bool IsValid() => true;
};

from roslyn.

alrz avatar alrz commented on August 26, 2024

This looks more like a initialization block rather than class declaration. Also it could be implemented as a nested local type (#259) so naturally you would expect anonymous classes as well:

return new BaseClass() {
    public override bool IsValid() => true;
    ...
};

PS: comma was a typo, sorry.

from roslyn.

jcdickinson avatar jcdickinson commented on August 26, 2024

Within context of this issue/feature it's about anonymous types and we should likely extend syntax instead of breaking existing syntax.

from roslyn.

nvivo avatar nvivo commented on August 26, 2024

@ArlZ, these two look exactly the same to me:

IsValid() => true
public override bool IsValid() => true

adding modifiers doesn't change that, only makes more verbose.

from roslyn.

jcdickinson avatar jcdickinson commented on August 26, 2024

@nvivo I think @alrz is bringing in inspiration across from #259, which could succeed/replace this feature - but that has already been specced over on that issue. I prefer the more succinct syntax, like you, as anything more is entirely redundant and doesn't look like the current anonymous types at all.

from roslyn.

alrz avatar alrz commented on August 26, 2024

I'm talking about a more general feature like "implementing interfaces anonymously" instead of "anonymous types implementing interfaces". I borrowed all this from Java, though.

from roslyn.

gafter avatar gafter commented on August 26, 2024

It anonymity really important? Compared to local (within a block) class declaration as an alternative way of handling this. It is nice that this lets you stay in an expression context, it is true, but I do not think the use cases are really simplified much.

from roslyn.

jcdickinson avatar jcdickinson commented on August 26, 2024

It anonymity really important?

For Linq I'd assume it would be crucial.

public IEnumerable<ICustomer> GetCustomers() {
  return from c in db.Customers
        select new {
          Name = c.Name,
          Surname = c.Surname
        };
}

In addition:

  • Syntax already exists for anonymous types - why not re-use it instead of adding cruft?
  • Syntax already exists for classes - why not re-use it for block-scope classes?
  • Using pseudo-anonymous block-scope class initializers would result in two forms of syntax for exactly the same thing. E.g. The same problem already exists in C#:
    • When should you use a lambda?
    • When should you use a anonymous delegate?
  • What value do the publicity specifiers add? YAGNI.
  • What value do the return types add? YAGNI.

Does inventing new syntax here for anonymous-but-no-so-anonymous-types add anything at all? Even just one thing? Versus adding either nothing (if method declarations are not supported) or re-using the lambda grammar (if method declarations are supported); both also have significantly less keystrokes, significantly less indentation and are far easier to human-parse. Less syntax makes a language good, not more. Once you have added syntax you can never remove it, in opposition: using existing syntax should be largely familiar to experienced developers.

from roslyn.

svick avatar svick commented on August 26, 2024

@Porges A lot of that boilerplate could be also removed by using a record (part of #206).

from roslyn.

aluanhaddad avatar aluanhaddad commented on August 26, 2024

It anonymity really important? Compared to local (within a block) class declaration as an alternative way of handling this. It is nice that this lets you stay in an expression context, it is true, but I do not think the use cases are really simplified much.

@gafter Are local type declarations still on the table? To me this is all about scoping.

from roslyn.

aluanhaddad avatar aluanhaddad commented on August 26, 2024

In addition to scoping, I think capturing generic parameters could make this quite useful.

from roslyn.

alrz avatar alrz commented on August 26, 2024

@aluanhaddad #9523

from roslyn.

aluanhaddad avatar aluanhaddad commented on August 26, 2024

@alrz Thanks!

from roslyn.

arfilon avatar arfilon commented on August 26, 2024

I does not have to be perfect , it is anonymous types after all , i think implementing the interface geter without extra syntax like in the (t00 commented on Jul 24, 2015) cover 90% of the day to day need.

the idea is not to have full functional class, to do that just use a private class, we need to have ability to pass data when interface required, just like what we do in anonymous type in linq ,if the code try to consume the set method ,show an error or throw an Exception at run time, just like anonymous types.

tuple that can't implementing interface, will not solve the problem.

from roslyn.

nvivo avatar nvivo commented on August 26, 2024

I still think this is a very required feature, but this issue has been closed and I don't believe the team will respond this issue again.

Someone with time to discuss should open a new issue proposing a simpler version of this and see what can get out of it.

from roslyn.

jnm2 avatar jnm2 commented on August 26, 2024

I'm willing to give that a try first.

from roslyn.

jbtibor avatar jbtibor commented on August 26, 2024

@gafter Are there local classes in C#? Or this is a future feature? I agree that local classes would make anonymous interface implementations redundant.

from roslyn.

jnm2 avatar jnm2 commented on August 26, 2024

@Spacefish And well I know it. I was answering @jbtibor's question, "Are there local classes in C#? Or this is a future feature?"

from roslyn.

svick avatar svick commented on August 26, 2024

@RUSshy See the comment above: #13 (comment)

We have no expectation of ever doing anything like this.

Also, this kind of issue now belongs to the csharplang repo, and there is a very similar request already opened there: dotnet/csharplang#1542.

from roslyn.

HaloFour avatar HaloFour commented on August 26, 2024

Similar but not quite. It might be worth opening a separate issue. I agree that it doesn't seem likely that it will happen given the tepid response from some team members, but I do think that they would be very useful especially when it comes to Android interop.

from roslyn.

gafter avatar gafter commented on August 26, 2024

Feature requests for C# can be opened in https://github.com/dotnet/csharplang

from roslyn.

CyrusNajmabadi avatar CyrusNajmabadi commented on August 26, 2024

sounds like that would just be a waste of time:

You never know. Someone might champion it. If it is not opened, it certainly won't happen though.

from roslyn.

dan-lugg avatar dan-lugg commented on August 26, 2024

Feature requests for C# can be opened in https://github.com/dotnet/csharplang

sounds like that would just be a waste of time:

We have no expectation of ever doing anything like this.

"We will never make a 32-bit operating system."
Bill Gates (speaking at the launch of MSX in 1989).

from roslyn.

FANMixco avatar FANMixco commented on August 26, 2024

This should be brought to C#!

Give your votes here:
dotnet/csharplang#4301

from roslyn.

HaloFour avatar HaloFour commented on August 26, 2024

@vbjay

Being able to do something like ... would be useful.

Under what circumstances would that be better than using on the disposables themselves? Even with the original proposal here there's nothing to suggest that the implemented interface would be automatically delegated to any, let alone all, of the members of the anonymous type.

from roslyn.

vbjay avatar vbjay commented on August 26, 2024

Well in one place is in Observable.Using call. Create an anonymous object wrapping different items to use as resources and in the Observable factory part can use the resource object items.

from roslyn.

vbjay avatar vbjay commented on August 26, 2024

I understand I can create a class and write the code but having anonymous objects able to implement IDisposable and have it create disposable implimentation that disposes items that are disposable would be useful.

I get the problem of creating an anonymous object with a member pointing to something IDisposable that exists outside of anonymous object and then that object is disposed because the anonymous object was disposed.

from roslyn.

vbjay avatar vbjay commented on August 26, 2024

Maybe like key keyword in vb when creating a comparable anonymous object, a new keyword could be out in front of members we want disposed. If that keyword is used at all in that anonymous creation then it is IDisposable and items marked by keyword get added to items that are disposed.

var x = new { Dispose SomeIDisposable x = Blaaa}

Something like that.

from roslyn.

HaloFour avatar HaloFour commented on August 26, 2024

@vbjay

I'd suggest opening a new discussion on the csharplang repository if that's something you want to suggest. This particular issue is already closed and this repository isn't used to propose new language features anymore.

from roslyn.

jnm2 avatar jnm2 commented on August 26, 2024

@tmat has started a discussion on this: dotnet/csharplang#6049

from roslyn.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.