In Which @Captain asks C# Beginner Questions



  • @blakeyrat said in In Which @Captain asks C# Beginner Questions:

    @Captain It also doesn't care if you add a trailing comma:

    list = [
      theFirst,
      theSecond,
      theThird,
    ];
    

    Which is brilliant and every programming language should support it dammit.

    So that you can remove the comma later, call it "refactoring" and get a bonus 0,5h on the burndown chart. 16 commas in different features and you can have the rest of the day off!



  • @Captain said in In Which @Captain asks C# Beginner Questions:

    and have the IDE do all the scaffolding

    Not sure what kind of scaffolding you need. How would it even treat two different files? Just concat them together?

    Either way, from what I know PoshTools isn't included by default, but installing VS extensions is generally a painless process. Haven't really used it though - I mostly use PowerShell as a, well, shell.



  • @Maciejasjmj said in In Which @Captain asks C# Beginner Questions:

    Not sure what kind of scaffolding you need. How would it even treat two different files? Just concat them together?

    I don't know. How does PowerShell do libraries? It does do libraries, right? Like, I can define functions and pull import them into my script and then run the script, right?

    All I know is that I need to run the same command on like 1500 mailboxes, so obviously I'm going to make a function and an array with the mailboxes (ideally I'll be able to have PS build that list for me) and then I'll map over the list. And it "has" to be PowerShell, since I'm just a beginner at C# and not very interested in learning how to call PS cmdlets from C#.


  • Considered Harmful

    @Captain I don't have much PowerShell experience. I do know that in VS15 (not 2015) you can load up a folder now without a "project" per se. That would probably be more appropriate for an interpreted language like PowerShell (or anything not requiring MSBuild, really).



  • Speaking of weird whitespace issues, TIL that C# doesn't like newlines in its ternary operators. VS is complaining about missing semicolons in:

        static string source_of_income_code(int income, String source)
        {
             income == 0                     ? return "None"
           : income == 1                     ? return "Unknown"
           : source == "None" && income > 0  ? return "Unknown"
           : return source
           ;
        }
    

    which makes C# ternary operators pretty useless. :-(

    The weird thing is that the ternary operator's documentation explicitly says that it's right associative -- so this is just a parsing issue.

    I don't get it.

        static string normalized_source_of_income(int income, String source)
        {
           return ( income == 0                     ? "None"
                  : income == 1                     ? "Unknown"
                  : source == "None" && income > 0  ? "Unknown"
                  : source
                  );
    
        }
    

    worked okay. I guess it's some weird limitation from not treating statements as first class values.



  • @Captain said in In Which @Captain asks C# Beginner Questions:

    It does do libraries, right? Like, I can define functions and pull import them into my script and then run the script, right?

    Typically it's just .ps1 scripts. They can directly call .NET methods from libraries natively, but don't usually have libraries of their own, because that isn't how powershell is meant to be used.

    @Captain said in In Which @Captain asks C# Beginner Questions:

    Speaking of weird whitespace issues, TIL that C# doesn't like newlines in its ternary operators. VS is complaining about missing semicolons in:

    It's not the newlines, its the returns. Turnaries are purely value based. That should read:

    private static string SourceOfIncomeCode(int income, string source)
    {
       return income == 0                ? "None"
       : income == 1                     ? "Unknown"
       : source == "None" && income > 0  ? "Unknown"
       : source
       ;
    }
    


  • @Captain said in In Which @Captain asks C# Beginner Questions:

    worked okay. I guess it's some weird limitation from not treating statements as first class values.

    It's more that you just can't return mid-stat-



  • And a point on style:

    It's not terribly important, but some things people generally agree on are that all methods in C# should be PascalCase, all variables should be camelCase, and not really anything should be snake_case. Additionally, it's generally preferred to use the keyword forms of built in types when possible, as then there is no risk of someone reusing the class name. I and many others also add access modifiers, even when they're the default, just so that we signal our intent to the maximum extent possible: class members are private, namespace-level types are internal.



  • @Captain said in In Which @Captain asks C# Beginner Questions:

    which makes C# ternary operators pretty useless.

    ? You can't put returns in them, if that's what you mean. It has nothing to do with your newlines. You're using it for flow control? I guess? It doesn't work that way in C#.



  • @Magus said in In Which @Captain asks C# Beginner Questions:

    private static string SourceOfIncomeCode(int income, string source)
    {
       return income == 0                ? "None"
       : income == 1                     ? "Unknown"
       : source == "None" && income > 0  ? "Unknown"
       : source
       ;
    }
    

    and beyond the syntax issues, I'd generally expect that to be written as a series of if statements. ternary within ternary is usually red flag.



  • @fwd Well, alternatively:

    private static string SourceOfIncomeCode(int income, string source)
        => income == 0                     ? "None"
         : income == 1                     ? "Unknown"
         : source == "None" && income > 0  ? "Unknown"
         : source;
    


  • @fwd YUKK



  • @Magus I don't know that syntax (but I like what I see). What does => mean?



  • @Magus said in In Which @Captain asks C# Beginner Questions:

    @fwd Well, alternatively:

    private static string SourceOfIncomeCode(int income, string source)
        => income == 0                     ? "None"
         : income == 1                     ? "Unknown"
         : source == "None" && income > 0  ? "Unknown"
         : source;
    

    I don't follow, that's still using nested ternaries.



  • @fwd said in In Which @Captain asks C# Beginner Questions:

    ternary within ternary is usually red flag.

    Eh, for a terse switch-case it's okay. Of course then are things like:

    a == 0 ? (b == 0 ? c : (d ? e : f)) : (d == f ? a : (b == 0 ? c : d))
    

    (only usually with less parentheses to boot, because that would make things somewhat readable, and we'll have readable over our dead bodies).



  • @Captain It's new C#6 syntax. That's the 'goes to' operator, usually used in delegates:

    list.Select(item => item.Name);
    

    converts a list of objects to an enumeration of the values of their name properties, which is evaluated lazily.

    They added it as method or property syntax with VS15.

    You might find it useful with, say, Action:

    Action thing = () => Console.WriteLine("Hello world!");
    thing();
    
    // Or
    
    Action<string> print = text => Console.WriteLine(text);
    print("Hello world!");
    

    Note that this last block of code has been valid since around VS2010



  • @Maciejasjmj said in In Which @Captain asks C# Beginner Questions:

    @fwd said in In Which @Captain asks C# Beginner Questions:

    ternary within ternary is usually red flag.

    Eh, for a terse switch-case it's okay. Of course then are things like:

    a == 0 ? (b == 0 ? c : (d ? e : f)) : (d == f ? a : (b == 0 ? c : d))
    

    (only usually with less parentheses to boot, because that would make things somewhat readable, and we'll have readable over our dead bodies).

    yeah, that's worst case. it's no so bad nicely formatted as in the original example, but format document will eat those extra spaces. it just strikes me as a "look how smart I am" thing rather than taking the obvious, immediately readable albeit very slightly longer approach.



  • @fwd nested ternaries for guards are immediately obvious.

      condition1 ? result1
    : condition2 ? result2
    : condition3 ? result3
    : defaultResult


  • @Captain A switch isn't much different, though, and has a dedicated default case. Though since that requires const cases, it wouldn't work for you anyway.



  • @Captain said in In Which @Captain asks C# Beginner Questions:

    @fwd nested ternaries for guards are immediately obvious.

      condition1 ? result1
    : condition2 ? result2
    : condition3 ? result3
    : defaultResult
    

    like I said, it's less readable than using if-return for every case, and even less so when you can't maintain your ?'s in the same column in the editor. ctrl+k, ctrl+d is basically involuntary for me at this point.



  • @Magus agreed.

    Not to get all pro-Haskell, but it has both guards (which accept boolean expressions, like the ternary-switch) and cases, which accept arbitrary expressions and let you pattern match. Haskell cases are more like the C# switch, but I think with richer pattern matching semantics (I'll look into C#'s more later).



  • @fwd said in In Which @Captain asks C# Beginner Questions:

    like I said, it's less readable than using if-return for every case

    Yeah, you said that. But it's not.

    You're just not familiar with the style.



  • @Magus said in In Which @Captain asks C# Beginner Questions:

    A switch isn't much different

    Personally I find it much different - switches should be used for flow control, and ternary chains for value-to-value mappings (preferably without side effects). Although I guess that's a question of style.

    Plus the limitations are pretty much the exact opposite - switch has severely limited conditions (at least the C# one - VB is much more lenient), but can accept a full flow for each case, while ternaries can do fancy conditions, but should only really return a value.

    Eh. else if takes care of everything anyway.



  • @Captain For pattern matching in C#, we generally use LINQ's methods.

    @Captain said in In Which @Captain asks C# Beginner Questions:

    Yeah, you said that. But it's not.
    You're just not familiar with the style.

    It's not just that. VS has really good breakpoints, but you can't break mid-statement. In this case, it's short and not problematic, but in the general case it's preferred to give things their own breakable lines. It isn't an issue of correctness.



  • @Captain said in In Which @Captain asks C# Beginner Questions:

    @fwd said in In Which @Captain asks C# Beginner Questions:

    like I said, it's less readable than using if-return for every case

    Yeah, you said that. But it's not.

    You're just not familiar with the style.

    but it is, and I'd wager most people reading c# code would agree with me. my lack of familiarity (if you want to call it that) is due to people not using that pattern, probably because they prefer maintainability over cleverness.



  • @Captain said in In Which @Captain asks C# Beginner Questions:

    Not to get all pro-Haskell,

    Liar.



  • @fwd Only in the general case. Here, whatever, it's simple and no harder to debug.



  • @Maciejasjmj said in In Which @Captain asks C# Beginner Questions:

    Personally I find it much different - switches should be used for flow control, and ternary chains for value-to-value mappings (preferably without side effects). Although I guess that's a question of style.

    They should be formally equivalent, but that would require C#'s switch to get a bit smarter.

    What I'm getting at is that you can always translate

     switch (variable)
     {
         case 0: result0;
         case 1: result1;
         case 2: result2;\
         default: defaultResult
     }
    

    into

       variable == 0 ? result0
     : variable == 1 ? result1
     : variable == 2 ? result2
     : defaultResult
    

    But going the other way around can require language features C# just doesn't have.



  • @Captain I'm actually really okay with this, though. Switch or turnary, you end up with a bunch of magic values and repetition.

    Sometimes you need it, but imo it's best if it's as dumb as possible.



  • @fwd said in In Which @Captain asks C# Beginner Questions:

    but it is, and I'd wager most people reading c# code would agree with me.

    Hate to agree with @Captain, but... not really. if-else if chains are the same, just more verbose, are still bad formatting since else if is a hidden else without braces smell, and require you to repeat the return or assignment in each case.



  • @Captain said in In Which @Captain asks C# Beginner Questions:

    What I'm getting at is that you can always translate

     switch (variable)
     {
         case 0: result0;
         case 1: result1;
         case 2: result2;\
         default: defaultResult
     }
    

    Mind that a switch doesn't return the value of case expression, it just executes the code in it. This example would either trip the compiler or do nothing, don't remember now - and you can't do

    var x = switch (variable)
    {
        case 0: result0;
        default: resultDefault;
    }
    


  • @blakeyrat it's the language I know best. So yeah, I want to know how C# compares to what I know.

    And there is a valid use for "switches" that check to see if an expression matches some value under equality and "switches" that let you run arbitrary queries on the expression you're testing.



  • @Maciejasjmj said in In Which @Captain asks C# Beginner Questions:

    @fwd said in In Which @Captain asks C# Beginner Questions:

    but it is, and I'd wager most people reading c# code would agree with me.

    Hate to agree with @Captain, but... not really. if-else if chains are the same, just more verbose, are still bad formatting since else if is a hidden else without braces smell, and require you to repeat the return or assignment in each case.

    I don't get what you're saying here?

    since we're looking to return in this example, there's no need to have an else keyword anywhere in this. having to repeat return for each case seems like a minor point.

    I'd be surprised if I was in the minority here. doing a quick search for "nested ternary" brings up results mostly for "what is this" and "is bad"



  • @fwd It's like everything else.

    C# has a goto keyword, even.

    You've picked a really weird case to object to.



  • @Magus said in In Which @Captain asks C# Beginner Questions:

    @fwd It's like everything else.

    C# has a goto keyword, even.

    You've picked a really weird case to object to.

    I feel like everyone else has picked a weird case to defend.



  • @fwd Simple logic to filter incorrect values from simple input, with only three cases and a default, all of which are clearly visible, pure, and have no state?

    If there was any case where this is acceptable syntax, it's here.



  • @Magus said in In Which @Captain asks C# Beginner Questions:

    @fwd Simple logic to filter incorrect values from simple input, with only three cases and a default, all of which are clearly visible, pure, and have no state?

    If there was any case where this is acceptable syntax, it's here.

    that's kind of my point. if you have to stretch to find an acceptable use, why bother? you're not gaining much, and that bit of code is going to look different than most of your other code. consistency is a benefit.



  • @fwd said in In Which @Captain asks C# Beginner Questions:

    that's kind of my point. if you have to stretch to find an acceptable use, why bother? you're not gaining much, and that bit of code is going to look different than most of your other code. consistency is a benefit.

    :wtf:

    This isn't a stretch. This is an acceptable use. It works, it's easy to understand, and it's simple.

    You're denying it for purely religious reasons at this point.



  • @Magus said in In Which @Captain asks C# Beginner Questions:

    @fwd said in In Which @Captain asks C# Beginner Questions:

    that's kind of my point. if you have to stretch to find an acceptable use, why bother? you're not gaining much, and that bit of code is going to look different than most of your other code. consistency is a benefit.

    :wtf:

    This isn't a stretch. This is an acceptable use. It works, it's easy to understand, and it's simple.

    You're denying it for purely religious reasons at this point.

    if you're going to say it's acceptable in this very simple case, but imply it's probably not in most others, I'm calling that a stretch.

    my reasons are 1. it's harder to read, ranging from "not much" in this case to "a lot" in any more complex case, and 2. there's no benefit for the tradeoff. 1 is subjective, but again I think I'm in the majority there, where 2 is pretty objective. neither is religious. I'd say "use this pattern because you can" is the religious argument here.


  • Considered Harmful

    @Magus It depends on circumstances. I've found value in keeping code simple and straightforward, if nothing else to avoid confusing the junior devs on the team.
    My usual problem with the ternary operator is that it's used as an expression, not a statement, so it often gets crammed into a bigger statement. Statements should't try to do too much at once.
    You can use it responsibly, but not everyone does.



  • @error by the same token, however, it should not be discouraged to use something well just because it can be used badly. If it's being used well, it's good code.



  • @fwd said in In Which @Captain asks C# Beginner Questions:

    @Magus said in In Which @Captain asks C# Beginner Questions:

    @fwd Simple logic to filter incorrect values from simple input, with only three cases and a default, all of which are clearly visible, pure, and have no state?

    If there was any case where this is acceptable syntax, it's here.

    that's kind of my point. if you have to stretch to find an acceptable use, why bother? you're not gaining much, and that bit of code is going to look different than most of your other code. consistency is a benefit.

    It looks like a list of conditions and value pairs, with funny delimiters. It's not that different from the rest of my code.


  • Discourse touched me in a no-no place

    @error said in In Which @Captain asks C# Beginner Questions:

    You can use it responsibly, but not everyone does.

    Not everyone uses simple loops responsibly either. There's no worthwhile feature that cannot be abused by the foolish…


  • kills Dumbledore

    I'm kind of with @fwd here. Nested ternaries are generally discouraged, which means even simple ones like what we're arguing over here are rarely seen. That adds some cognitive load, simply because it's unfamiliar to most people who'll see it.

    I wouldn't be too phased by something like this, but would write it as a switch or series of ifs if I was writing the same code. Anything much more complicated would be a nono



  • OK, here's another question. I have a Visual Studio C# project, and I have a long database query in my Program.cs file, saved to a string variable. Is there any way I can put the query in a separate file and just read the contents of that file into a variable?

    I mean, I know I can write Query.cs instead, but I'd rather have a pure SQL text file if possible.


  • Considered Harmful

    @Captain Yes, you can definitely do that. I'd recommend, though, you put that query into a stored procedure and just call that.



  • @error Stored procedures aren't a possibility for me (the database engine kind of sucks).



  • I guess maybe what I'm asking about is a bit ambiguous. I don't want to have to deploy the SQL file when I deploy the application, but have the SQL query compiled into the program.



  • @Captain haskell is the language you know best?
    what solar system are you from?


  • Considered Harmful

    Here's reading the file:

    string query;
    using( var sr = new StreamReader( @"foo.sql", Encoding.UTF8 ) ) {
    	query = sr.ReadToEnd();
    	sr.Close();
    }
    

    Executing the query is left as an exercise for the reader.


Log in to reply