This project is read-only.

"with" blocks

Topics: C# Language Design
May 3, 2014 at 7:11 PM
I believe that the C# language should support a "with" block construct akin to the With/End With block in VB. For those unfamiliar with the VB keyword, please read the MSDN entry here.

I'm aware of the quiet controversy surrounding the keyword and why it hasn't been added to C#, but year after year people keep asking for it, and many of us dearly miss the convenience, so I'll go ahead and be "that guy" and re-open the discussion here.

The syntax would be quite simple:
with(target)
{
    .someProperty = "value";
    .someMethod();
}
I think the arguments in favor of the construct are simple, obvious, and probably well known: it's extremely convenient when you have a large number of properties to set or methods to call, and those of us with any sort of VB background miss it (speaking for myself, it's probably the only thing I miss from VB, and I used VB before it was even called VB).

Apparently in the earliest days of .NET (née NGWS) Eric Gunnerson posted on gotdotnet.com either a discussion or a list of reasons why it wasn't included. That site is gone, and I don't recall ever reading that post so I'm not sure what those reasons were. I have also heard about a list of reasons provided nearly ten years ago by Scott Wiltamuth, a Group Program Manager for Visual C#. The MSDN blog is also long gone as far as I can tell, but I found three points quoted on StackOverflow in response to one of many posts seeking a C# "with" equivalent. They're the closest thing I've found to an "official" explanation about why this keyword hasn't been added:
  • Small or non-existent readability benefits.
  • Increased language complexity.
  • C++ heritage.
With respect, I have to say that I don't find any of these reasons remotely compelling.

Readability is simply a matter of opinion and many people clearly hold exactly the opposite opinion. (Where was the "readability" argument when lambda expressions were designed?)

I simply don't believe it would be particularly complex to implement. The .NET compilers accomplish many dramatically complicated feats of optimization and transformation, but remembering that a line beginning with a period should be prefixed by the enclosing "with" target doesn't strike me as a major coding effort.

I have never felt that C# had much in common with C++ (thankfully), but I think it's safe to say that in 2014 we've left C++ behind a long, long time ago.

I am also aware of two frequently-repeated "unofficial" arguments against the keyword:
  • You can lose track when the block contains many lines.
  • Nesting creates ambiguity.
Although it's a common argument, I dismiss the first one as irrelevant. Buy a bigger monitor. Use a smaller font. Scroll. This is largely the "readability" argument all over again, and I feel it is very weak. Generally speaking, most tools can be abused. This is rarely a good reason to avoid responsible use of the tool.

Ambiguity deserves consideration. If the targets of the outer and inner "with" blocks have the same member available, which one takes precedence? To me it seems logical to assume the nearest scope (the innermost block). Perhaps strongly-typed targets should throw a compiler warning. I could also see the argument for a full-on compiler error, and a runtime error for dynamic or weakly-typed targets. C# is full of arbitrary decisions of this nature. I would even settle for a prohibition on nested "with" blocks. This is not an intractable problem.

Who's with me?
May 5, 2014 at 11:57 AM
Edited May 5, 2014 at 11:58 AM
I'm only partially with you. Personally, I've never needed a with block, except for initialization.

Currently, it's easy to write:
new C {
  Property1 = ...,
  Property2 = ...
};
but you can't replace the constructor call by a factory:
CreateC() {
  Property1 = ...,
  Property2 = ...
};
My proposal is to allow a syntax similar to initializers, but starting with any expression, not only a constructor.
expression { initialization-list };
The majors points being:
  • The syntax is similar to what already exists with new.
  • There are no ambiguities: only assignments can be made.
  • The scope of usage is reduced (contrary to your proposal, you can't open a with block and just forget that you're inside one).
  • This is a single expression, not a list of statements: it's easy to use in expression trees.
  • It's of the same type as expression.
I'm aware our proposals are quite different: is mine useful enough to you?
May 5, 2014 at 2:59 PM
Edited May 5, 2014 at 3:01 PM
Thanks for the reply.

I suppose I don't understand why there is opposition to something which is both simple and convenient, and the comment "contrary to your proposal, you can't open a with block and just forget that you're inside one" doesn't make any sense to me at all. Have you never been four or five layers deep in if and for blocks? It's just the nature of the beast. I don't believe programmers often forget where they are, or we wouldn't have much success writing code of any sort.

It's ironic that you note that initializing with a factory is not an option. That is similar to the reason I started thinking about with blocks again. A few years ago I was really into the IoC thing. I did some bugfixing on Ninject, and did the whole circuit with Windsor and TinyIoC etc. I found that the IoC model (object instances which are always just there when you need them) is an excellent example of finding yourself having to do a series of initializer calls against the same element without the new syntax being available.

I find that people usually associate the with concept with new initialization, but the usefulness of the feature is best compared to the using statement. After all, you don't actually need all those using entries at the start of your code, you could just re-type endless series of giant namespace sequences. The 'using' statement was created to avoid repetition -- just like 'with' in VB.

So I do appreciate the input, but no, I wouldn't say your proposal addresses the need.

The nearest approximation I've seen to with so far is to declare a very tightly-scoped variable, such as the following (or, if you like, wrapping the first line in a using statement, I believe the end result is the same):
{
    SomeObject x = Stuff.Which.IsTedious.ToRetype;
    x.SomeProperty = 123;
    x.SomeMethod();
}
I haven't looked at how this gets compiled, but I imagine the compiler optimizes this in exactly the manner I would expect a with block to be expanded. I have used this approach myself but it "feels" ugly to me, even if I'm right in assuming the compiler optimizes away the variable. (In some discussions the "SomeObject" type isn't even declared, instead people just use var and let the runtime figure it out, which is simultaneously more like with in usage but a bit worse in terms of runtime overhead.)

Interestingly, the solution above isn't commonly hit upon. You will often see suggestions of even more elaborate work-arounds -- extension methods with generics is a common solution -- but to my eye, at least, these all end up being even more ugly. They require me to pause and think about what the code is doing, whereas a simple with block is quite obvious and clean.
May 5, 2014 at 3:40 PM
I have to agree with MrJul on this one. The only place I've wanted a "with" construct is in initializing an object coming back from a factory or an object pool, and re-using the existing initialization syntax for that would be highly preferable.
May 5, 2014 at 4:44 PM
I am also in total agreement with MrJul on this.

In fact, I was surprised the C# team didn't come up a syntax for (re)initializing existing objects when they introduced object initializers in the first place.
May 5, 2014 at 4:53 PM
In vb.net, the code:
With arrayOfRects[someExpr]
  .X += .Width;
End With
will evaluate the lvalue arrayOfPoints[someExpr] exactly once, so the access of .X and .Width are guaranteed to use the same instance of Rectangle; that guarantee would hold even if some other evil thread modifies arrayOfPoints in the meantime [even when code isn't thread-safe, it's often desirable to limit the damage that can be done by erroneous threading in cases where it doesn't cost anything] . The only clean and efficient way to achieve similar semantics in C# would be:
void AdjustRect(ref Rectangle rect)
{
  rect.X += rect.Width;
}
...
AdjustRect(ref arrayOfRects[someExpr]);
Perhaps it would be possible to use a lambda in such a way as to avoid the overhead of a delegate invocation, but I don't think there's any way to yield code which would get turned into a non-virtual method call which the JITter could optimize out.
May 6, 2014 at 6:40 AM
Edited May 6, 2014 at 7:04 PM
What is the advantage of this:
with (some.long.path.to.target)
{
    .X = 5;
    .DoWork();
    .Y = 10;
}
and what MV10 suggested:
{
    var x = some.long.path.to.target
    x.X = 5;
    x.DoWork();
    x.Y = 10;
}
Same number of lines and removes a bit of ambiguity. The one fault I can see is that it always feels odd to me to have arbitrary scopes in my code.
May 6, 2014 at 7:01 PM
Edited May 6, 2014 at 7:03 PM
Micah, the preceding post from supercat brings up an interesting issue about thread safety which counts as a pretty big difference if with could be added to C# in a way that matches VB's guarantee. The approach which declares a variable simply wouldn't have those protections. My interest in VB stopped cold at VB6 (in which threading was only accomplished through tricky Win32 hacks) so the thread-safety aspect of VB.NET's with is very interesting news to me. I wonder how it is accomplished, actually. VB/C# aside, I'm not sure how you could do this with the .NET libraries...

Although it's interesting that VB.NET provides this guarantee, on the C# side of the house, I'm not sure a proposed with structure warrants any special considerations. After all, if you wrote out the same property and method calls "long-hand" you'd still have to manage thread-safety if that was a legitimate concern in your program. I can't say I'd have ever expected code inside a with block to be treated any differently in that respect.

I freely admit I see it only as tasty, tasty syntactic sugar.

More subjectively, Micah, it is my opinion that the with version makes it much more obvious what the programmer is doing and why, compared to an anonymous, limited-scope block like the var example.
May 6, 2014 at 10:11 PM
MV10 wrote:
Micah, the preceding post from supercat brings up an interesting issue about thread safety which counts as a pretty big difference if with could be added to C# in a way that matches VB's guarantee. The approach which declares a variable simply wouldn't have those protections.
I think that dragging thread safety into this is dangerous, VB's With doesn't really have anything to do with threading. For reference types Micah's code is identical to the code generate by With. For value types things as are a bit more interesting. As supercat shows, With generates something that has no equivalent in C#
ref Rect rc = arrayOfRects[someExpr];
rc.X += rc.Width;
If the arrayOfRects variable is not local this protects you from other threads that could change it. But it does not protect you from other threads that change the contents of the array, without a lock or Interlocked.Add this code suffers from a race condition no matter what. Besides, you could achieve the a similar effect by using:
var rcs = this.arrayOfRects;
rcs[someExpr].X += rcs[someExpr].Width;
(Unless someExpr can change too in which case you'd need to copy it to a local too)

So yes, it is pure syntactic sugar, it doesn't do anything that can't be achieved by other means.
May 6, 2014 at 11:12 PM
I agree re threading, but speaking as someone who cut his teeth on assembly in the late 70s, you say that like syntactic sugar is bad thing. :)
May 6, 2014 at 11:51 PM
mdanes wrote:
Besides, you could achieve the a similar effect by using ...
(Unless someExpr can change too in which case you'd need to copy it to a local too)
I tend to be a big fan of the DRY principle. Although
With Foo( expr1() , expr2() )
  .X += 3
  .Y += 5
End With
could be emulated in C via
Point[,] t1 = Foo;
int i1 = expr1();
int i2 = expr2();
t1[i1,i2].X += 3;
t1[i1,i2].Y += 5;
having to take snapshots of the array variable and all the indices is rather verbose. Worse, code which doesn't take snapshots of those things but merely assumes they won't change could get broken if it is later modified in such a way that does modify them.

Perhaps I'm overly cautious about such things, but to my mind, saying something multiple times creates the possibility that they might (intentionally or unintentionally) be edited so as to be different, and should, as much as practical, imply a degree of independence among the repeated things.
May 7, 2014 at 12:29 AM
MV10 wrote:
I agree re threading, but speaking as someone who cut his teeth on assembly in the late 70s, you say that like syntactic sugar is bad thing. :)
Too much syntactic sugar causes syntactic cavities.
May 7, 2014 at 12:54 AM
nmgafter wrote:
MV10 wrote:
I agree re threading, but speaking as someone who cut his teeth on assembly in the late 70s, you say that like syntactic sugar is bad thing. :)
Too much syntactic sugar causes syntactic cavities.
I'm a believer in "write what you mean". It's not possible for a language to be perfectly expressive, but if the programmer doesn't really want to do two separate array-index look-ups, code written with a syntax that only requires one is more accurately indicative of intended meaning than would be code that writes the array-look-up operation twice.

I'm not a big fan of the way extended methods are implemented, and would consider them the kind of sugar that causes cavities, since using instance-member syntax to call a static member of a totally unrelated class isn't "writing what one means". If extension methods had been written using a .., however, I'd be a much bigger fan since it would be clear that the purpose of the code was to invoke a static method from among those which use the proper type.
May 7, 2014 at 2:20 PM
Edited May 7, 2014 at 2:26 PM
I was going to get snarky and ask whether the same people who oppose with also take the time to avoid using and explicitly write every single namespace throughout their code, but ironically, yesterday I was reminded the question is valid without sarcasm. I inherited a gigantic, complicated banking application and spent much of the day resolving many instances of namespace ambiguity errors. The reality is that using is actually far less specific than would be the case in a with block.

In an even bigger coincidence, this app's DAL is loaded with repetitive code to hydrate classes from database results, which I realized is a prime example of where with would be nice to have. Not that I'd hydrate a POCO this way, except that a different approach isn't even an option -- our corporate astronaut architects mandate this process, and as you might imagine with a giant complex financial app, some of these returns are enormous.

But this led to an additional realization about worries that a with block might grow too large to comprehend (a concern which I still find bizarre). Even in this poorly-architected banking application, I find that most methods are tight enough that it's very unlikely you'd find enough sprawl to lose your place.

I definitely agree with you, supercat, about extension properties. Like using namespace ambiguities, I think C# has far-less-clear syntax in many places, and there is certainly no shortage of syntactic sugar. Heck, LINQ is almost nothing but syntactic sugar...

However, at this point I fear I'm starting to repeat myself, so I suppose I'm beating a dead horse. I remain staunchly unconvinced that there is a solid reason for concern about this construct, and a few seconds on Google should make it obvious that it has been a popular wishlist item since C# was first exposed to the world, but barring any new angles on the question, I'll drop the issue.

Thanks for the discussion.
May 7, 2014 at 5:10 PM
MV10 wrote:
However, at this point I fear I'm starting to repeat myself, so I suppose I'm beating a dead horse. I remain staunchly unconvinced that there is a solid reason for concern about this construct, and a few seconds on Google should make it obvious that it has been a popular wishlist item since C# was first exposed to the world, but barring any new angles on the question, I'll drop the issue.
There's a tremendous amount of inertia on many issues; someone declares something is a bad idea, even if only a few things would have to change for it to become a good idea, and even if those things in fact do change, in many people's minds it will forever be a "bad idea". Further, many people seem unable to grasp the concept that fact that something has become historical practice does not mean it should forevermore be considered a good idea. Although FORTRAN allowed the use of .GE., .LT., etc. as aliases of > and < by keypunch operators who lacked those characters, the use of such dotted-letter tokens was never really preferred, and since initially (from what I recall) integers did not implicitly promote to real in the earliest versions of the language, the expression I/J could be used to without having to worry about an expression like X=I/J being ambiguous (it would need to be written as either X=REAL(I/J) or X=REAL(I)/REAL(J), and either alternative would be clear. The addition of implicit integer-to-real conversion made the intention of X=I/J ambiguous, but the syntax already existed and had to remain valid. Thus even today we're stuck with languages that follow FORTRAN's lead, rather than recognizing that whole-number division and real-number division are fundamentally different and should be treated as such. VB.NET recognizes the distinction; C# does not.

There's really only one place I can see where a With could introduce ambiguities, and that would in the parsing of future operators like ?. If an expression is legally allowed to start with a . and a letter, and if a widening conversion exists between a reference type and Boolean, then the character sequence ?.foo could be legally parsed as ? .foo. My own personal preference would be for it to in fact parse exactly like that (essentially behaving as a with on the left-hand operand), though I think a "with" operator would be even better.

Incidentally, it may be worth noting that one of the biggest advantages of with arises when using aggregate variables ("mutable structures"). Aggregate variables are not objects, and are thus offensive to those who believe everything should be considered an object. Rather than a fix few slight problems in the way .NET languages handle aggregate variables, it's easier to declare that they're "evil". The fact that With would, with a slight enhancement, allow the pattern:
with (myListOfCoordinates[index])
{
  .X += 3;
  .Y += 1;
}
to be written without regard for whether the coordinate type was a struct or class (the enhancement would be to say that if myListOfCoordinates is a read-write property of structure type, it should expand as:
var temp1 = myListOfCoordinates; // If anything could change it
var temp2 = index; // If anything could change it
var temp3 = temp1[temp2]
temp3.X += 3;
temp3.Y += 1;
temp1[temp2]=temp3;
thus updating the values in the list). I think the with form would be much cleaner than a form which needs to explicitly read out the structure, modify it, and write it back. I doubt the "mutable structs are evil" people would go for such usage, since from what I can tell, they think
var temp = myListOfCoordinates[index];
myListOfCoordinates[index] = new coordinateOfSomeSort(temp.X+3, temp.Y+1);
is somehow clearer.
May 7, 2014 at 8:10 PM
supercat wrote:
mdanes wrote:
Besides, you could achieve the a similar effect by using ...
(Unless someExpr can change too in which case you'd need to copy it to a local too)
I tend to be a big fan of the DRY principle. Although...
Me too but With has limited value in this regard, it stops being useful as soon as another array needs to be used in the With block. This is a more general issue of With, it's good only when a single object needs to be accessed in this way, in all other situations (and I don't think they're uncommon) you're left with 2 choices: not using With at all or mixing With with the "classic" approach.
Worse, code which doesn't take snapshots of those things but merely assumes they won't change could get broken if it is later modified in such a way that does modify them.
In general, when I write code I don't assume anything, I know that variables I'm using change or do not change. You will probably say that many people actually assume many things about the code and you'd be right. But you can't really go and tell people that they should start using With everywhere because this might save them from variables that change without them being aware of that.

With is what it is, a convenience feature and its primary goal is to save some typing when you need to set (or get, in some cases it can be useful too) 10 properties of the same object. The rest of the described advantages are just side effects and many people will be oblivious to those.
they think
var temp = myListOfCoordinates[index];
myListOfCoordinates[index] = new coordinateOfSomeSort(temp.X+3, temp.Y+1);
is somehow clearer.
Well, it isn't clearer but the obvious solution would be design the types in such a way that you can write:
myListOfCoordinates[index] += new offsetOfSomeSort(3, 1);
May 7, 2014 at 8:56 PM
All I can say regarding with is that watching the Roslyn VB.NET forums that clearly it introduces as many problems as it intends to solve. The most amusing being the ability to re-reference the "withed" expression from within the with block and introducing new keywords for that purpose.

In my opinion, with saves so little typing and doesn't really solve any problems that can't already easily be solved. For normal reference types it does nothing that a temporary variable can't achieve. It could add some voodoo around modifying structs returned from the "withed" expression, as has been mentioned in this thread, but I'd be concerned that the nature and behavior of such an operation would be a little unintuitive (when does the value get copied back? What happens if there is an exception mid-way?). I do like the concept of created-object initializers as that probably handles the majority of use cases anyway.

That said, at least nobody is suggesting copying JavaScript's abomination of a with implementation. :)
May 7, 2014 at 10:31 PM
mdanes wrote:
Me too but With has limited value in this regard, it stops being useful as soon as another array needs to be used in the With block. This is a more general issue of With, it's good only when a single object needs to be accessed in this way, in all other situations (and I don't think they're uncommon) you're left with 2 choices: not using With at all or mixing With with the "classic" approach.
I don't disagree with you; a cleaner approach would be to have a means of assigning scope-limited identifiers to byrefs.

Perhaps something like with (var foo := someArray[index]), and allowing members to be accessed as foo.this and foo.that would be to your liking? Using := rather than = should make clear that the statement is not an ordinary assignment.
In general, when I write code I don't assume anything, I know that variables I'm using change or do not change. You will probably say that many people actually assume many things about the code and you'd be right. But you can't really go and tell people that they should start using With everywhere because this might save them from variables that change without them being aware of that.

With is what it is, a convenience feature and its primary goal is to save some typing when you need to set (or get, in some cases it can be useful too) 10 properties of the same object. The rest of the described advantages are just side effects and many people will be oblivious to those.
The behavior of With when applied to structures is more than just a side-effect.
Well, it isn't clearer but the obvious solution would be design the types in such a way that you can write:

```C#
myListOfCoordinates[index] += new offsetOfSomeSort(3, 1);
That would be better if .NET allowed += and other such operators to be defined so as to take a ref as their first argument, and especially if collections included, and the language supported, a method or family of methods similar to
void ActUpon<TExtra>(int index, ActionRR<T,TExtra> proc, ref TExtra extra)
{
  if (index < 0 && index >= _Count) throw Exception(...);
  proc(ref _array[index], ref extra);
}
such that the above code could be turned into:
myListOfCoordiantes.ActUpon<CoordinateOffset>(index, (ref Coordinate p1, ref CoordinateOffset p2) => operator_AddAssign(ref p1, p2), ref theOffset);
assuming theOffset happened to be a variable; if it's a new expression, it could be generated within the lambda and the TExtra would just be the type of some arbitrary dummy variable which would be ignored by the expression. Note the use of ref TExtra means there's no need for the code to generate a closure.

[note: efficiency would be even better if it were possible to declare a var ref syntax, which would be equivalent to ref except that it would expressly authorize the compiler to pass a copy when necessary or convenient. Basically, it would direct the compiler to behave as it does when passing this to struct members, except that programmers could limit such behavior to those parameters for which it would be appropriate.
May 7, 2014 at 10:55 PM
Maybe real life example would be beneficial (note; I didn't write the code, just inherited it)
_reportViewer.LocalReport.DataSources.Clear()
_reportViewer.LocalReport.DataSources.Add(reportDataSource1)
_reportViewer.LocalReport.ReportPath = BackgroundPath & "\Templates\Report.rdlc"
_reportViewer.LocalReport.EnableExternalImages = True
_reportViewer.LocalReport.SetParameters(New ReportParameter() {tbTitle})
_reportViewer.LocalReport.SetParameters(New ReportParameter() {columnTitle})
_reportViewer.LocalReport.SetParameters(New ReportParameter() {columnFirstname})
_reportViewer.LocalReport.SetParameters(New ReportParameter() {columnSurname})
_reportViewer.LocalReport.SetParameters(New ReportParameter() {columnAccessLevel})
_reportViewer.LocalReport.SetParameters(New ReportParameter() {pTime})
_reportViewer.LocalReport.SetParameters(New ReportParameter() {pDate})
_reportViewer.LocalReport.SetParameters(New ReportParameter() {pPage})
_reportViewer.LocalReport.SetParameters(New ReportParameter() {pOf})
_reportViewer.LocalReport.SetParameters(New ReportParameter() {CustomLogoPath})
_reportViewer.LocalReport.SetParameters(New ReportParameter() {ShowCustomLogo})
_reportViewer.RefreshReport()
Now utilising With
With _reportViewer
{
  With .LocalReport
  {
    With .DataSources
    {
      .Clear()
      .Add(reportDataSource1)
    }
    .ReportPath = BackgroundPath & "\Templates\Report.rdlc"
    .EnableExternalImages = True
    .SetParameters(New ReportParameter() {tbTitle})
    .SetParameters(New ReportParameter() {columnTitle})
    .SetParameters(New ReportParameter() {columnFirstname})
    .SetParameters(New ReportParameter() {columnSurname})
    .SetParameters(New ReportParameter() {columnAccessLevel})
    .SetParameters(New ReportParameter() {pTime})
    .SetParameters(New ReportParameter() {pDate})
    .SetParameters(New ReportParameter() {pPage})
    .SetParameters(New ReportParameter() {pOf})
    .SetParameters(New ReportParameter() {CustomLogoPath})
    .SetParameters(New ReportParameter() {ShowCustomLogo})
   }
  .RefreshReport()
}
May 8, 2014 at 12:54 AM
Which is semantically and nearly syntactically equivalent to the following:
var rv = _reportViewer;
var ds = lr.DataSources;
var lr = rv.LocalReport;
ds.Clear();
ds.Add(reportDataSource1);
lr.ReportPath = BackgroundPath + "\Templates\Report.rdlc";
lr.EnableExternalImages = true;
lr.SetParameters(New ReportParameter() {tbTitle});
lr.SetParameters(New ReportParameter() {columnTitle});
lr.SetParameters(New ReportParameter() {columnFirstname});
lr.SetParameters(New ReportParameter() {columnSurname});
lr.SetParameters(New ReportParameter() {columnAccessLevel});
lr.SetParameters(New ReportParameter() {pTime});
lr.SetParameters(New ReportParameter() {pDate});
lr.SetParameters(New ReportParameter() {pPage});
lr.SetParameters(New ReportParameter() {pOf});
lr.SetParameters(New ReportParameter() {CustomLogoPath});
lr.SetParameters(New ReportParameter() {ShowCustomLogo});
rv.RefreshReport();
And that's my point, as shorthand with doesn't buy you a whole lot. What you lose, as the VB.NET forums point out, is that ability to then reference that hidden temporary variable.
May 8, 2014 at 3:42 AM
What you lose, as the VB.NET forums point out, is that ability to then reference that hidden temporary variable.
I still don't see why that matters. The point is to eliminate repetitive junk. As using does. Thread safety, weird off-the-wall reference tricks -- this is entirely irrelevant.

AdamSpeight2008's example is much like my DAL hydration junk in my banking app -- tons of tedious repetition, which simply goes away if with is available.

Dreaming up new weird uses for it isn't useful. Suggesting somebody might want to reference multiple arguments or whatever -- not useful. It's a simple expand-at-compile-time shortcut. You can't bake bread or brew beer without sugar. Syntactic sugar is good. Tools are good. Simplicity is good. I'll only live a finite span of time, I want to spend less of it typing.
May 8, 2014 at 6:01 AM
MV10 wrote:
Thanks for the reply.
I suppose I don't understand why there is opposition to something which is both simple and convenient, and the comment "contrary to your proposal, you can't open a with block and just forget that you're inside one" doesn't make any sense to me at all. Have you never been four or five layers deep in if and for blocks? It's just the nature of the beast. I don't believe programmers often forget where they are, or we wouldn't have much success writing code of any sort.
Personally, I think the "Have you never been four or five layers deep in if and for blocks?" argument, is not very compelling. Unless one is optimizing an important hot path in their code, what benefit is there to nesting imperative control structures to that depth, it often hampers readability and maintainability for no gain.

However, I think the argument for readability is more compelling.

In this vein, I think MrJul's factory initializer suggestion would be very valuable
CreateC() {
  Property1 = ...,
  Property2 = ...
};
Allowing factory methods to return objects whose properties could be assigned in an initializer list would have several advantages including :

a. Reduced dependence on constructors
b. Increased syntactic flexibility leading to cleaner APIs.
c. Furthering the general trend toward declarative constructs in C#.
May 20, 2014 at 4:55 AM
I received an email about C# vNext, which led me here after several hours of perusing all this great thought. I had to sign in and vote on this particular item, because it was something that I had wanted in the past. It is not so much anything I have dealt with lately. It depends on application architecture as to how relevant it may be. But it always did seem like a nice-to-have in C#.
The intent of some features is at times somewhat less academic or esoteric than how people this close to the internals of the C# language may see it. That's not always the case, and I am glad that it is not, since I have always enjoyed exploring intellectual frontiers in the languages (always looking for the kind of excitement like what lambdas and Linq and generics provided; async/await, etc.) This particular request is really, to me, just one of those features of practicality. One simply may not want to have to repeat the same thing on perhaps dozens of lines of code when accessing properties of an object.
I see some examples of other ways to achieve this in C#, but none of them negate the usefulness of having a with () {} block with their brevity. This notation of a with block is very concise. If you think that there would be ambiguity in determining to which variable the dot operations apply, that could be overcome with IntelliSense or some other visual cue (like line connectors or a hover-over "black light" or "map layer" that reveals more contextual information about what you are looking at).

Thanks for listening! I've been saving up some years of saying "Great job!" on all this stuff, but since I am here... Great job and thanks! I'll step back out of the thread now.
May 20, 2014 at 12:23 PM
MV10 wrote:
What you lose, as the VB.NET forums point out, is that ability to then reference that hidden temporary variable.
I still don't see why that matters. The point is to eliminate repetitive junk. As using does. Thread safety, weird off-the-wall reference tricks -- this is entirely irrelevant.

AdamSpeight2008's example is much like my DAL hydration junk in my banking app -- tons of tedious repetition, which simply goes away if with is available.

Dreaming up new weird uses for it isn't useful. Suggesting somebody might want to reference multiple arguments or whatever -- not useful. It's a simple expand-at-compile-time shortcut. You can't bake bread or brew beer without sugar. Syntactic sugar is good. Tools are good. Simplicity is good. I'll only live a finite span of time, I want to spend less of it typing.
You can avoid that repetition now by the use of simple shorthand temporary variables, which was what my example demonstrated. And with in not an expand-at-compile-time shortcut, it's literally nothing more than an unnamed temporary variable. AdamSpeight2008's code sample turns exactly into my code sample by the compiler except that with the inclusion of parenthesis, blocks and newlines it actually requires more characters than just using temporary variables.
May 20, 2014 at 12:51 PM
Edited May 20, 2014 at 12:51 PM
Halo_Four wrote:
And with in not an expand-at-compile-time shortcut, it's literally nothing more than an unnamed temporary variable.
Ok, agreed, and creating a temporary variable (whether explicitly or behind-the-scenes) to save some typing is, to me, the ugly solution. Therefore, I hereby change my suggestion from a new keyword to a #with directive such that it does expand-at-compile-time, good-old C-macro-style, as that is all I believe we really need to accomplish this functionality in 99% of all reasonable use-cases.

So, none of the with opponents will volunteer to start writing their code with full-namespace expansion, foregoing the entirely unnecessary using shortcut? :)

(Hmm, come to think of it, I wonder why the alias/namespace form of using wasn't defined as #using? Not to mention the less-common extern alias keyword combo... both are compiler directives, AFAIK neither of them have any IL runtime equivalent/impact...)
May 20, 2014 at 2:53 PM
MV10 wrote:
Halo_Four wrote:
So, none of the with opponents will volunteer to start writing their code with full-namespace expansion, foregoing the entirely unnecessary using shortcut? :)

(Hmm, come to think of it, I wonder why the alias/namespace form of using wasn't defined as #using? Not to mention the less-common extern alias keyword combo... both are compiler directives, AFAIK neither of them have any IL runtime equivalent/impact...)
Why? C#'s heritage is C++ and C++ has a using namespace clause that behaves in the exact same manner.

This isn't a question as to whether or not syntax candy is good. Clearly it's good or we'd all still be twiddlin' bits in machine language. But it also needs to have a purpose that vastly outweighs the expense of amending the language and it needs to fit within the charter and heritage of that language. The argument about with in C# predates the release of C# by some time and the decisions were made at that time based on the heritage of the language and how easy the "problem" is to solve without it, even back before we had shorthand for an inferred variable type. I haven't seen anything that invalidates those arguments and not a single use case that can't be accomplished without it.
Jun 5, 2014 at 3:55 PM
I agree with introduction of 'with'. No matter that you can scratch right ear with left hand - matter is HOW EASY it can be.
We're not SELLING language, but IMPROVING it - who cares how much money you can earn with that feature??
EVERY syntactic sugar can be completely removed, because there is one low level way to do it. But wait... you made 'em! So you simplified life only where YOU like it? What about us, programmers on C#?
Syntactic sugar is like an electric window in car - you CAN live without it, but your lazy ass prefer to press button than turn lever, right? Here is the same - if we're forced to dig in low level C#, let's simplify as much as possible our life!
Jun 5, 2014 at 5:27 PM
Halo_Four wrote:
Dreaming up new weird uses for it isn't useful. Suggesting somebody might want to reference multiple arguments or whatever -- not useful. It's a simple expand-at-compile-time shortcut. You can't bake bread or brew beer without sugar. Syntactic sugar is good. Tools are good. Simplicity is good. I'll only live a finite span of time, I want to spend less of it typing.
A with statement which could regard the specified parameter as an "alias" [or ref] rather than a value would help with DRY in many usage scenarios, and should not cause confusion if the syntax made clear what was expected:
with(get set x := myList(index))
{
   x = (x+1) & 7;
}
would be equivalent to:
var x = myList(index);
   x = (x+1) & 7;
myList(index) = x;
but would only require myList(index) be specified once, and the scope of the declaration would be limited to the place the variable is supposed to be used. If only get is specified, the value of x would be read-only within the scope; if only set is specified, it could not be used before code wrote it. If ref is specified, the right-hand expression would have to be a storage location [i.e. a field or an array slot] but code in the with block could use it as a ref parameter. Not a momentous life-changing feature, but it would IMHO make code cleaner in cases where it's necessary to use a property in a way which doesn't quite fit any compound-assignment operators.