-
Notifications
You must be signed in to change notification settings - Fork 1k
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
Proposal: not
keyword for if
and while
#157
Comments
I have made bugs where I didn't notice the ! quite a few times. One workaround is to use (!(expression)) but that doesn't look pretty (visually busy). I like your suggestion better; much more readable. |
I was once propose There are some argument in there |
I don't know that this suggested syntax really feels right for C#, but I agree it would be nice to have a clearer way to express the common pattern of negating a whole expression. The |
I read dotnet/roslyn#7927 an there are some valid arguments in there. Actually for beginners it might be a good idea, with respect to all C syntax derived languages, to stick with With namespace MyTools
{
internal static class BinaryLogic
{
public static bool not(bool expression) => !expression;
}
} and use it like using static MyTools.BinaryLogic;
class AClass
{
void ProcessValue(int value)
{
if ( not( value >= 0 )) { ... }
}
} I just put it in some places of existing code of mine. Looks good enough for me 😄 |
I think you just implemented your own proposal. I'd never thought of just adding a |
@DavidArno You're welcome 😁 |
@lachbaer I like the way you're thinking with the static function, I'll probably steal that in a few places. So simple and nice. I'm probably getting out of the scope of what really matters here, but it is worth noting that there's one (perhaps minor) disadvantage to this in that automated refactoring tools (think Resharper offering I'm probably over engineering this one. |
I usually go with public static class BoolExtensions
{
public static bool Not(this bool b) => !b;
} or simply if (getDataServiceCallResult.MessageHeader.IsSuccess.Not()) { ... } |
So the void MyFunction(int b) {
if not (b>0)
throw new ArgumentOutOfRangeException();
bool finished = false;
while not (finished) {
// have your own interpretation here ;-)
}
} would simply compile to void MyFunction(int b) {
if (!b>0)
throw new ArgumentOutOfRangeException();
bool finished = false;
while (!finished) {
// have your own interpretation here ;-)
}
} I think my only change would be in the placement of where the // The not applies to the entire expression
if (not(b > 0 && c < 10)) { }
// The not only applies to the b > 0 expression
if (not(b > 0) && c < 10) { } (That's effectively the same syntax as the extension method @lachbaer showed, just that it's part of the language syntax rather than an extension which means refactoring and other tooling would understand it.) |
I guess this one should stay in VB rather than included in C#. You can always use local functions (#56) to do this: void MyFunction(int b)
{
Func<bool, bool> not = val => !val;
if (not (b>0))
throw new ArgumentOutOfRangeException();
bool finished = false;
while (not (finished)) {
// have your own interpretation here ;-)
}
} |
What about adding the keywords 'unless' and 'until'? void MyFunction(int b)
{
unless (b > 0)
throw new ArgumentOutOfRangeException();
bool finished = false;
until (finished) {
// do stuff
}
} |
I don't like the idea of throwing new keywords around that do nothing more than what existing operators do today. If I were to affect the syntax in any way to make this "more readable*", I might relax the syntax of condition expressions to allow for void MyFunction(int b) {
if !(b>0)
throw new ArgumentOutOfRangeException();
bool finished = false;
while !(finished) {
// have your own interpretation here ;-)
}
} As whitespace is effectively optional here it would be the same as adding * A painfully dubious term on which you're likely to find very little consensus. |
@Aurequi Me, too, don't like the idea of introducing too much new keywords. @HaloFour The main idea was to make |
@lachbaer I think the ultimate goal isn't to make negation more verbose, it's to make it stand out. Verbosity is one way to achieve that, but I think putting the |
@Aurequi logical statements should be positively formulated in order to make them more easily understandable. this reduces the error rate. By this locic, I'd disagree with the |
besides, you should probably avoid to use |
What if VS added a separate highlighting rule for |
Usually the problem with hard to read not's in the code goes away with refactoring: if (!(value >= 0)) becomes if (value < 0) and if (!(b > 0) && c < 10) becomes if (b <= 0 && c < 10) becomes if (IsSomeNamedConditionMet(b, c)) |
Problem is |
@Thaina, I'd suggest that if you do |
@DavidArno Well sure I just point out that it not always the same And sometimes it just subtle like if(!(obj.child?[key]?.transform.position.y >= 0))
{
} |
Sorry, but I strongly disagree. Not always is the positive expression the one that is best understandable. Otherwise we wouldn't have the negation in our natural speaking. You'll always say "When you don't do your homework immediately you'll be grounded" instead of "You might either go out or stay home after your homework is done". 😁 Or in code: if (! homeworkIsDone)
groundYourKid();
// instead of
if (homeworkIsDone)
allowKidToEitherGoOutOrDoWhateverSHeLikes(); The main reason we write negative statements is that we think it that way first. And mostly even when reading code I'd go with the thinking the code shows to me. |
@Thaina then don't do it! Instead, refactor and name things properly. I use your example: // find the 4 bugs in this code...
if (objectTree.Child?[key].Transform(matrix).Position.Y >= 0)
{
// ...
} and refactor to var elementOrNull = objectTreeOrNull?.Child?[key];
var transformedElementOrNull = elementOrNull?.Transform(matrix);
var positionOrNull = transformedElementOrNull?.Position;
var yPositionOrNull = positionOrNull?.Y;
// this now should be a no-brainer
if (yPositionOrNull != null && yPositionOrNull >= 0)
{
// ...
} and then refactor to var positionOrNull = GetPositionForTransformedElementOrNull(key, matrix);
var yPositionOrNull = positionOrNull?.Y;
if (IsPositive(yPositionOrNull))
{
// ...
} |
About refactoring: Especially in that state the code looks a bit 'ugly' and the more opportunities there are to already formatting it understandable on the fly the better. Not to mention, that often code once written stays that way. C# isn't only used in big programming companies 😉 By the way |
Red -> green -> refactor. If you aren't refactoring as you go, then that suggests you aren't using TDD. Why not? 😝 |
@DavidArno Indeed I most often don't as I don't work on major projects for a living. And sure I am not the only one out there using C#... |
@lachbaer "you are writing your code you will normally not do refactoring on the go" This is a false statement. In a matter of fact, I do refactorings like this all the time. One of my mottos is "refactoring is thinking". The above refactorings not only improve readability, but also decrease the cyclomatic complexity. So it also improves understandability and reduces the amount of testing I need to do. |
@MovGP0 Don't take 'you' personally (from Oxford: "Used to refer to any person in general"), in Germany we would say "man" meaning that there are a mentionable amout of people to who it applies. |
@jnm2 First, I compare it to Second. Both
And even said it out loud |
I reviewed this discussion. A big part is about how things could or should be written instead of changing the language specification. This seems a bit too starry-eyed to me! Sorry... I won't say that many of the suggestions aren't really recommendable. But in the real world - that counts all programmers - a lot will write code a different way. As we all might have experienced already on one or two days, the I tried some code samples in the editor and must say, that just putting the if ( !isFoobar) { }
// vs. //
if !( isFoobar ) { } That is, 1. because after Also other boolean operators (e.g. the proposed For the same reason I will vote for a |
It makes a big difference ... to you. To me, for example, the thing that stands out in both is your spaces inside the The point is, there is no correct form of a syntax that everyone finds the most readable. You, and others may well find |
@DavidArno Actually |
The more different ways there are to represent the same thing, especially when they're quite similar as these are, the more likely people are to misread them, in my opinion. Somebody used to |
If somebody implements A statement like Two more new keywords like I will soon write more about the reason, why this could be of more importance than it looks on first sight. The reason lies in one of my favorite topics human factors. |
Before I dive into the reasoning for respecting the human factors on this topic I want to tell that Roslyn is already partly prepared for supporting Now about the human factors When you review this, and other, discussion you might notice that there - objectively spoken - doesn't seem to be a right and wrong on the ways different programmers think. You can argue that there exist dont But when talking about the thinking of an expression flow, then we must respect the way our brains sort and coordinate those expressions. And as enlightend people we now that there is not only one way. E.g. above there was a discussion whether conditions should mainly expressed and rewritten as being true. But some disagreed, because a negative expression seems more expressive to them in certain cases. Why can it be so? One reason may lie in the cultural and language basis. For example in Turkish a sentence can have multiple negative statements and the sentence still stays negative. In English like in German a double negative can make the whole expression a positive outcome, like in mathematics. But it ain't not necessarily so 😉 Social influences must also be accounted for. For some people the glass is still half full whereas for others the glass is already half empty. So, long story short, I want to encourage you to respect these human factors more! Though @TheOtherSamP wrote in another context
The reason for supporting Also the appearance of The support for I'm keen to hear your comments on this! 😃 |
The only comment I feel worth making at this stage is this: this proposal (at the time of writing) has 16 👎's and no 👍's, so you are flogging a dead horse here continuing to argue for it. Sometimes, we just have to accept in life that we lost the argument and move on... |
@DavidArno |
If they do not join in the discussion, how can we know their views? Also, as there is a huge range of opinion amongst the folk who do come here, then I'd suggest it is extremely unlikely that - despite all that varying opinion being united in its opposition to this idea - that there are lots of folk out there amongst the silent, who agree with your proposal. |
I think I'm going to implement these two instructions (as optional feature), as it will probably be not too much effort. Then people can see for themselfs how they feel in use. |
If have posted in another discussion something that makes use of do
ifnot ((line = Console.ReadLine()).StartsWith("#"))
lines.Add(line);
until (line.StartsWith("$")); |
@lachbaer this code is hard to understand. LINQ would make much more sense for this problem: declare a helper: private IEnumerable<string> ReadLinesFromConsole() {
yield return Console.ReadLine();
} declare some extensions: public static IEnumerable<string> WithoutComments(this IEnumerable<string> lines) {
return lines.Where(line => !line.StartsWith("#"));
}
public static IEnumerable<string> UntilEndOfScript(this IEnumerable<string> lines) {
return lines.TakeWhile((line, index) => !line.StartsWith("$"));
} Now you can write your intention in a clean and easily understandable way: return ReadLinesFromConsole().WithoutComments().UntilEndOfScript(); |
@MovGP0 That is an elegant solution with very litte letters and expressions for this very problem 🎃 |
@lachbaer LINQ has the additional benefit, that you can implement some additional extensions to remove the public static IEnumerable<T> Except<T>(this IEnumerable<T> enumeralbe, Func<T, bool> predicate) {
return enumeralbe.Where(item => !predicate(item));
}
public static IEnumerable<T> TakeUntil(IEnumerable<T> enumeralbe, Func<T, int, bool> predicate) {
return enumerable.TakeWhile((item, index) => !predicate(item, index));
} |
Lately I came to my senses 😉 C# is a C syntax derived language, as many other languages are. There is no If there is a negative "not" condition and you don't like its "lookings" then either
I'll keep this proposal for comments for some days before closing it. |
I like the proposed until keyword. I'd use it. |
I'd actually use it, too, and am not done with it. Recently I had evidence that it can prevent semantic errors, because of that human factors I have mentioned several times already. I will open another proposal that solely concerns Can we start a poll on any web platform somehow and ask whether "'using' would be used if it was existing in C#"? (Not if one likes it, simply if one would use it or stick with 'while') |
Here's an argument for 'until': it can prevent some double negatives, which can introduce bugs due to poor readability. I don't have a good code example ready right now... |
That depends on how one sees things. Assume a badly designed 3rd party with unfortunate property names. while (!person.HasNoJob) person.GotoWork(); This is a double negation. You imply that because of the "negation operator" Or you can use a more verbose form, that eliminates the "negation operator" and lets the "IsNotFull" stay as the only negative statement: while (false == person.HasNoJob) person.GotoWork(); Just because it has a longer and more verbose beginning We can argue whether 'while (false ==' can be seen in meaning as a double negation also or not. Because there will certainly be different opinions on that - and I guess by my guts that when asking programmers of different levels it will roughly be 50/50 - there can be no definite one and only answer on whether using 'while (!' or 'while (false =='. Finally there is the possibility to create a simple tool function while (asUntil(person.HasNoJob)) person.GotoWork(); |
Ups, the whole twisting of negating here and there made me make a nonsense example in the post above 😁 I'm going to update it to something serious. Hold on... |
the until(person.HasJob)
{
// search and apply for a job
} |
@MovGP0 I was looking for double negations, one being the '!' and the other a property with a verbal negative identifier |
A However, an additional |
https://en.cppreference.com/w/cpp/language/operator_alternative Python has this alternatives as well - they are good. Among new languages there is also a |
This proposal is about readibility. Many things of C# go in that direction, like LINQ and the new
match
expressions.Many conditions must be negative. But instead of using the slender and easy to overlook
!
the negation should go with the main expressionAs you can see
not
as a keyword stands afterif
andwhile
and not as part of the expression.In my eyes it is much more readable! Could be a light extension with a big use.
The text was updated successfully, but these errors were encountered: