Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
gariig
Dec 31, 2004
Beaten into submission by my fiance
Pillbug

GrumpyDoctor posted:

Was the old behavior originally intended, or was it a bug? That behavior seems incredibly counterintuitive to me, especially because, if I understand right, there's no way to explicitly request it anywhere in the language.

(Also, how did I not know that?)

C# code:
foreach (string keyword in keywords)
{
  query = query.Where (p => p.Description.Contains (keyword));
}
var results = query.ToList();
The old way makes complete sense if you think about it (as a compiler). I recreated the old code without the temporary variable. What you are creating is a closure over the variable keyword not the value of keyword. When the code goes to evaluate query using ToList all of the Where clauses captured keyword which would be the last value in keywords.

I'm glad Microsoft "fixed" this behavior to do what a normal human being would expect. Which is to have each Where clause capture the value of keyword by using the temporary variable.

Also, I didn't realize multiple Where clauses were cumulative (is that the right term?). I learned something new.

EDIT: VVVV It totally makes sense. I just never thought of it that way. At least Ithaqua didn't realize it. I take solace in that

gariig fucked around with this message at 17:12 on Sep 16, 2014

Adbot
ADBOT LOVES YOU

Sedro
Dec 31, 2008
Where clauses are normally cumulative, so why would Linq-to-Entities/Linq-to-SQL be any different?
C# code:
Enumerable.Range(1, 5).Where(x => x != 2).Where(x => x != 4); // 1, 3, 5

raminasi
Jan 25, 2005

a last drink with no ice

gariig posted:

C# code:
foreach (string keyword in keywords)
{
  query = query.Where (p => p.Description.Contains (keyword));
}
var results = query.ToList();
The old way makes complete sense if you think about it (as a compiler).

Well, yeah, but we're not compilers :argh: Score another point for immutability-by-default, I guess.

SirViver
Oct 22, 2008
Here's some more info about closures and loops.

New Yorp New Yorp
Jul 18, 2003

Only in Kenya.
Pillbug
[edit] dumb

New Yorp New Yorp fucked around with this message at 21:18 on Sep 16, 2014

Scaramouche
Mar 26, 2001

SPACE FACE! SPACE FACE!

Sedro posted:

C# code:
using (var contents = webClient.OpenRead(...))
using (var fs = File.Create(@"\path\to\file"))
{
    contents.CopyTo(fs);
}

You guys are way too good to me. That took care of that problem. However, that leads to

Another .NET problem (or possibly an sql problem)

I'm downloading these images, and then I'm updating the database with them so the item knows what it's image url is. However, I'm getting this message around halfway through*:
code:
System.Data.OleDb.OleDbException: Not enough storage is available to complete this operation
On the line that executes my stored proc, which is basically a InsertOrUpdate ItemID,ImageURL1,ImageURL2 kind of call. I'm surprised that this is happening, because I'm actually batching the statements per 1000 like so:
code:
Dim sql As New StringBuilder
Do While Not afile.EndOfStream
 Dim line = afile.ReadLine()
 Dim csv = line.Split(","c)
 '0 - ItemID
 '1 - Image1
 '2 - Image2

 If (stuff that confirms quality of the row in the csv) Then
  counter += 1
  sql.AppendLine("exec InsertOrUpdateThinger '" & Trim(csv(0)) & "','" & Trim(csv(1)) & "','" & Trim(csv(2)) & "'")
    If counter >= 1000 Then
     ExecuteSql(sql.ToString)
     counter = 0
     sql = New StringBuilder
    End If
 End If
Loop
ExecuteSql(sql.ToString)
So the idea being, the stringbuilder can only get up to 1000 rows before it gets sent off to the ExecuteSql function (where the error occurs), and the ExecuteSql after the loop will only catch the last <1000 rows. Is 1000 too much, or is this somehow occurring in the same scope/operation despite the batching? The InsertOrUpdate proc is a basic one like (from memory) select id from table where id=@id if @id is not null then update blah blah blah.

* Halfway being about 10,000 rows; There's only about 25,000 rows in the database >total<

New Yorp New Yorp
Jul 18, 2003

Only in Kenya.
Pillbug
Back to our LINQ chat, I did a quick test, and the way I thought it worked seems to be the way it actually works.

I think I confused myself earlier. Nevermind.

Bognar
Aug 4, 2011

I am the queen of France
Hot Rope Guy

Ithaqua posted:

I'd honestly never considered it before. I always assumed that multiple Wheres in LINQ to Objects wasn't cumulative, so doing that would iterate the list once, and give you 1,3,4,5. Then it would iterate the second list and give you 1,3,5. Of course, now that I think about it, it makes sense that it would be able to be optimized so the list is only iterated a single time.

The more you know.

It makes even more sense when you consider that LINQ to Entities doesn't actually come into play until you enumerate the query (.ToList() or otherwise). Until then, you're just building an expression tree that LINQ to Entities will eventually parse.

New Yorp New Yorp
Jul 18, 2003

Only in Kenya.
Pillbug

Bognar posted:

It makes even more sense when you consider that LINQ to Entities doesn't actually come into play until you enumerate the query (.ToList() or otherwise). Until then, you're just building an expression tree that LINQ to Entities will eventually parse.

Yeah, LINQ to Entities is a different story. I'm sure it doesn't generate any SQL until you run the query.

I think I was having a brain spasm at the line query = query.Where. I didn't read it as compounding LINQ methods on top of the original query, I just read it as reassigning the last method on top of the original. Dumb on my part. I retract everything I've ever said.

Sedro
Dec 31, 2008

Ithaqua posted:

I'd honestly never considered it before. I always assumed that multiple Wheres in LINQ to Objects wasn't cumulative, so doing that would iterate the list once, and give you 1,3,4,5. Then it would iterate the second list and give you 1,3,5. Of course, now that I think about it, it makes sense that it would be able to be optimized so the list is only iterated a single time.

The more you know.

It's usually safe to think of Linq iterating the list and producing a new list each time. Though with infinite lists, the laziness is no longer an optimization and actually necessary for correctness. For example you could create a random number generator, then transform it to get random numbers which are even.
C# code:
static IEnumerable<int> Randoms() {
  var random = new Random();
  while (true) yield return random.Next();
}

// if Where wasn't lazy this would never terminate
Randoms().Where(x => x % 2 == 0);
I like to think of IQueryable as transforming an SQL query instead of a sequence of values.
C# code:
SQL.Range(1, 5).Where(x => x != 2).Where(x => x != 4);
SQL("select i from ( values (1), (2), (3), (4), (5) ) as t(i)").Where(x => x != 2).Where(x => x != 4);
SQL("select i from ( select i from ( values (1), (2), (3), (4), (5) ) as t(i) ) t where i <> 2").Where(x => x != 4);
SQL("select i from ( select i from ( select i from ( values (1), (2), (3), (4), (5) ) as t(i) ) t where i <> 2 ) where i <> 4");

Bognar
Aug 4, 2011

I am the queen of France
Hot Rope Guy

Scaramouche posted:

So the idea being, the stringbuilder can only get up to 1000 rows before it gets sent off to the ExecuteSql function (where the error occurs), and the ExecuteSql after the loop will only catch the last <1000 rows. Is 1000 too much, or is this somehow occurring in the same scope/operation despite the batching? The InsertOrUpdate proc is a basic one like (from memory) select id from table where id=@id if @id is not null then update blah blah blah.

* Halfway being about 10,000 rows; There's only about 25,000 rows in the database >total<

Grab the ErrorCode from the OleDbException and Google around for that. Maybe also inspect the Errors property for additional information.

ljw1004
Jan 18, 2005

rum

Ithaqua posted:

I assume that's a C# 5 compiler thing, so it doesn't matter which framework version you're using, right?

Correct, it's a compiler thing and works on all target frameworks.


GrumpyDoctor posted:

Was the old behavior originally intended, or was it a bug? That behavior seems incredibly counterintuitive to me, especially because, if I understand right, there's no way to explicitly request it anywhere in the language. (Also, how did I not know that?)

The old behavior was just an oversight. The difference is only observable with lambdas. Prior to lambdas, there was no way to distinguish. When the compiler team added lambdas we just didn't even notice this one corner until it was too late.

A Tartan Tory
Mar 26, 2010

You call that a shotgun?!
New problem I'm afraid.

I want to do the following excel SUMPRODUCT calculation in C# and I'm not sure how to go about it within the current confines of my code.

code:
=SUMPRODUCT($M15:$M$37,$N15:$N$37,$R15:$R$37)/N14/R14
On line 14 (y0, m0), which is similar until we get to..

code:
=SUMPRODUCT($M37:$M$37,$N37:$N$37,$R37:$R$37)/N36/R36
...line 36 (y1, m10), which is the easiest calculation.

code:
=SUMPRODUCT($M$37:$M38,$N$37:$N38,$R$37:$R38)/N37/R37
Finally, line 37 (y1, m11), which is what it goes on for the rest of the inputs.

M, N and R are all stored in 2 dimensional arrays, based on the current year and month (M being SRCF, N being SRDiscFact and R being PrudentP).

code:
            for (y = 0; y < Years; y++)
            {
                for (m = 0; m < 12; m++)
                {
                    if (y == 0 && m == 0)
                    {
                        //arrays
                        PrudentP[y, m] = 1 * (1 - PrudentQ[y, m]);
                        SRCF[y, m] = SRExpenses[y, m] - URCharges[y, m];
                        SRDiscFact[y, m] = Math.Pow((1 + AIRM), -(((y + 1) * 12) - (12 - (m + 1))));
                    }

                    else if (y != 0 && m == 0)
                    {
                        //arrays
                        PrudentP[y, m] = PrudentP[y - 1, m + 11] * (1 - PrudentQ[y, m]);
                        SRCF[y, m] = SRExpenses[y, m] - URCharges[y, m];
                        SRDiscFact[y, m] = Math.Pow((1 + AIRM), -(((y + 1) * 12) - (12 - (m + 1))));

                    }
                    else
                    {
                        //arrays
                        PrudentP[y, m] = PrudentP[y, m - 1] * (1 - PrudentQ[y, m]);
                        SRCF[y, m] = SRExpenses[y, m] - URCharges[y, m];
                        SRDiscFact[y, m] = Math.Pow((1 + AIRM), -(((y + 1) * 12) - (12 - (m + 1))));

                    }
                }
            }

            for (m = 0; m < Months; m++)
            {
                if (m == 0)
                {
                    //arrays
                    PrudentP[y, m] = PrudentP[y - 1, m + 11] * (1 - PrudentQ[Years, m]);
                    SRCF[y, m] = SRExpenses[y, m] - URCharges[y, m];
                    SRDiscFact[y, m] = Math.Pow((1 + AIRM), -(((y + 1) * 12) - (12 - (m + 1))));

                }

                else
                {
                    //arrays
                    PrudentP[y, m] = PrudentP[y, m - 1] * (1 - PrudentQ[Years, m]);
                    SRCF[y, m] = SRExpenses[y, m] - URCharges[y, m];
                    SRDiscFact[y, m] = Math.Pow((1 + AIRM), -(((y + 1) * 12) - (12 - (m + 1))));

              }
            }
I have kinda, sorta figured out the following and also figured out I probably need to do another loop within each year/month, but I can't quite figure out how to structure the actual SUMPRODUCT calculation.

code:
            for (y = 0; y < Years; y++)
            {
                for (m = 0; m < 12; m++)
                {
                    if (y == 1 && m == 10)
                    {
                        //arrays
                        SterlingReserve[y, m] = ((SRCF[1, 11] * SRDiscFact[1, 11] * PrudentP[1, 11]) / SRDiscFact[1, 10]) / PrudentP[1, 10];
                        Console.WriteLine("SR  " + SterlingReserve[y, m]);
                    }

                    else if (y == 1 && m == 11)
                    {
                        //arrays
                        double calc1 = (SRCF[1, 11] * SRDiscFact[1, 11] * PrudentP[1, 11]) + (SRCF[2, 0] * SRDiscFact[2, 0] * PrudentP[2, 0]);
                        SterlingReserve[y, m] = calc1 / SRDiscFact[1, 11] / PrudentP[1, 11];
                        Console.WriteLine("SR  " + SterlingReserve[y, m]);
                    }

                    else if (y < 2)
                    {
                        //arrays
                        double sum = 0;
                        //This is where I'm starting to have trouble.

                    }

                    else
                    {
                        //arrays


                    }
                }
            }

            for (m = 0; m < Months; m++)
            {
                //arrays

            }
Should I try to convert the current values in the 2 dimensional array into a single dimension array, using the years and months? Is there an easier way to do this than a loop? And finally could someone give me a basic example (if they can0 of how to actually do such a loop?

A Tartan Tory fucked around with this message at 15:04 on Sep 17, 2014

raminasi
Jan 25, 2005

a last drink with no ice
Are you trying to calculate SUMPRODUCTs after you've already got the arrays, or do them on the fly as you generate the arrays? Your code is dense and your explanation is unclear. If it's the former, this function will get you what you want (without the division in the spreadsheet):

C# code:
double SumProduct(double[,] m, double[,] n, double[,] r, double yearCount)
{
    double sum = 0.0;
    for (int year = 0; year < yearCount; ++year)
    {
        for (int month = 0; month < 12; ++month)
        {
            sum += m[year, month] * n[year, month] * r[year, month];
        }
    }
    return sum;
}

A Tartan Tory
Mar 26, 2010

You call that a shotgun?!

GrumpyDoctor posted:

Are you trying to calculate SUMPRODUCTs after you've already got the arrays, or do them on the fly as you generate the arrays? Your code is dense and your explanation is unclear. If it's the former, this function will get you what you want (without the division in the spreadsheet):

C# code:
double SumProduct(double[,] m, double[,] n, double[,] r, double yearCount)
{
    double sum = 0.0;
    for (int year = 0; year < yearCount; ++year)
    {
        for (int month = 0; month < 12; ++month)
        {
            sum += m[year, month] * n[year, month] * r[year, month];
        }
    }
    return sum;
}

The arrays with the values the SUMPRODUCT is using have already been calculated, so I'll try this and see if I can get it to work, thanks!

Edit: Yeah I can't get this to work, it's displaying close numbers but they aren't correct and are going up instead of going down. Is there something I am missing? Are you sure I don't need the if/else statements?

code:

            for (y = 0; y < Years; y++)
            {
                for (m = 0; m < 12; m++)
                {
                    double sum = 0.0;
                    for (int year = 0; year < Years; ++year)
                    {
                        for (int month = 0; month < 12; ++month)
                        {
                            sum += SRCF[year, month] * SRDiscFact[year, month] * PrudentP[year, month];
                        }
                    }
                    SterlingReserve[y, m] = sum / SRDiscFact[y, m] / PrudentP[y, m];
                    Console.WriteLine("SR  " + SterlingReserve[y, m]);
                    Console.WriteLine("y  " + y);
                    Console.WriteLine("m  " + m);
                    Console.WriteLine("  ");
                }
            }
To clarify what I have and what I want to do with them. I have the arrays SRCF, SRDIscFact and PrudentP and want to use them to generate a SUMPRODUCT. They are already pre-calculated, this is a separate part of the program designed to populate a further array (SterlingReserve[y, m]) with the values of the SUM divided by some current values. So that the arrays can all be displayed later on in the program.

Also I'm trying to avoid multiple methods because they are confusing the gently caress out of me, really new to this, so doing it in the same method. I know it's stupid and dirty, but it's the only way I can understand atm.

Further edit: Have moved all the values into single dimension arrays in an attempt to understand what I am doing wrong. Still not getting it to work.

code:
                        double sum1 = 0;
                        for (int i = 0; i < 22 ; i++)
                        {
                            sum1 += SRCFProduct[i + 1] * SRDiscFactProduct[i + 1] * PrudentPProduct[i + 1];
                        }
                        SterlingReserve[y, m] = (sum1 / SRDiscFact[y, m]) / PrudentP[y, m];
                        Console.WriteLine("SR  " + SterlingReserve[y, m]);
                        Console.WriteLine("y  " + y);
                        Console.WriteLine("m  " + m);
                        Console.WriteLine("  ");

Just keeps giving me the same, the wrong value at the start that goes up instead of down.

A Tartan Tory fucked around with this message at 16:44 on Sep 17, 2014

New Yorp New Yorp
Jul 18, 2003

Only in Kenya.
Pillbug

A Tartan Tory posted:

Also I'm trying to avoid multiple methods because they are confusing the gently caress out of me, really new to this, so doing it in the same method. I know it's stupid and dirty, but it's the only way I can understand atm.

You really need to understand methods in order to write sane, maintainable code. What don't you understand about them?

Part of the problem that you're experiencing right now is that you've created a brittle tower of code that you don't quite understand, so anything you change just breaks it all and makes the problem worse.

Give a small example data set and the expected results and we can help you, your code is difficult to follow.

raminasi
Jan 25, 2005

a last drink with no ice
Oh, you don't just want the SUMPRODUCT. You want to do something with it. That's my bad; I didn't read your Excel formulas closely enough. But that's because I'm not great at Excel. Can you describe your problem without any technical concepts or code? (SUMPRODUCT is ok.) Pretend you're explaining to someone completely non-technical.

A Tartan Tory
Mar 26, 2010

You call that a shotgun?!

Ithaqua posted:

You really need to understand methods in order to write sane, maintainable code. What don't you understand about them?

Part of the problem that you're experiencing right now is that you've created a brittle tower of code that you don't quite understand, so anything you change just breaks it all and makes the problem worse.

Give a small example data set and the expected results and we can help you, your code is difficult to follow.

I know, in the actual main code section it's a tiny bit more readable, but any tips you have on making better methods would probably help out.

GrumpyDoctor posted:

Oh, you don't just want the SUMPRODUCT. You want to do something with it. That's my bad; I didn't read your Excel formulas closely enough. But that's because I'm not great at Excel. Can you describe your problem without any technical concepts or code? (SUMPRODUCT is ok.) Pretend you're explaining to someone completely non-technical.

Ok, basically what I want to do is this.

1. Pre-populate three arrays, based on the current year and month. (done)
2. Use those arrays to do a sumproduct, but to do it for every year and month in another loop so I can get the sumproduct for every y, m. (note the initial y, m is the next months array value, so for y0m0 it would start with the values from y0m1)
3. Use the sumproduct for every y, m and divide it by two current values also in an array based on y, m.
4. Save the final value in an another array based on the current y, m for future display.

I'm getting a little bit close to what I want, the values aren't completely correct but they are close and actually going down in value which is what I want.

code:
for (y = 0; y < Years; y++)
            {
                for (m = 0; m < 12; m++)
                {
                    if (y == 1 && m == 10)
                    {
                        //arrays
                        SterlingReserve[y, m] = ((SRCF[1, 11] * SRDiscFact[1, 11] * PrudentP[1, 11]) / SRDiscFact[1, 10]) / PrudentP[1, 10];
                        Console.WriteLine("SR  " + SterlingReserve[y, m]);
                        Console.WriteLine("y  " + y);
                        Console.WriteLine("m  " + m);
                        Console.WriteLine("  ");
                    }

                    else if (y == 1 && m == 11)
                    {
                        //arrays
                        double sum = (SRCF[1, 11] * SRDiscFact[1, 11] * PrudentP[1, 11]) + (SRCF[2, 0] * SRDiscFact[2, 0] * PrudentP[2, 0]);
                        SterlingReserve[y, m] = sum / SRDiscFact[1, 11] / PrudentP[1, 11];
                        Console.WriteLine("SR  " + SterlingReserve[y, m]);
                        Console.WriteLine("y  " + y);
                        Console.WriteLine("m  " + m);
                        Console.WriteLine("  ");
                    }

                    else if (y < 2)
                    {
                        //arrays
                        int current = ((y + 1) * 12) - (12 - m);
                        double sum = 0;
                        for (int i = current; i < 22 ; i++)
                        {
                            sum += SRCFProduct[i + 1] * SRDiscFactProduct[i + 1] * PrudentPProduct[i + 1];
                        }
                        SterlingReserve[y, m] = (sum / SRDiscFact[y, m]) / PrudentP[y, m];
                        Console.WriteLine("SR  " + SterlingReserve[y, m]);
                        Console.WriteLine("y  " + y);
                        Console.WriteLine("m  " + m);
                        Console.WriteLine("cur  " + current);
                        Console.WriteLine("  ");
                    }

                    else
                    {
                        //arrays


                    }
                }
            }

A Tartan Tory fucked around with this message at 17:07 on Sep 17, 2014

Newf
Feb 14, 2006
I appreciate hacky sack on a much deeper level than you.
If someone calls SomeClass SomeClassInstance = SomeClass.Load(key); with an invalid key, should the method return null or throw an exception or log some swear words or what? As far as I can tell I could go either route without much headache but I'm sure that this is something that has lots of established best practices.

fake edit: Please, look inside your mercy file... File Not Found.

raminasi
Jan 25, 2005

a last drink with no ice

A Tartan Tory posted:

Ok, basically what I want to do is this.

1. Pre-populate three arrays, based on the current year and month. (done)
2. Use those arrays to do a sumproduct, but to do it for every year and month in another loop so I can get the sumproduct for every y, m. (note the initial y, m is the next months array value, so for y0m0 it would start with the values from y0m1)
3. Use the sumproduct for every y, m and divide it by two current values also in an array based on y, m.
4. Save the final value in an another array based on the current y, m for future display.

Too technical. I'm an executive VP who's never programmed in my life. I don't know what "array" or "loop" means. Y? M? Just use English!

(I'm not just being a stickler to be an rear end; your fogginess about how to solve the problem is directly related to your fogginess about explaining it, I promise you.)

raminasi
Jan 25, 2005

a last drink with no ice

Newf posted:

If someone calls SomeClass SomeClassInstance = SomeClass.Load(key); with an invalid key, should the method return null or throw an exception or log some swear words or what? As far as I can tell I could go either route without much headache but I'm sure that this is something that has lots of established best practices.

fake edit: Please, look inside your mercy file... File Not Found.

With that little contextual information, I think the only advice anyone can reasonably give you is "All of those options are fine, as long as whatever you do is consistent with the rest of your codebase."

e: If there are multiple reasons that a key can be invalid, don't return null, because that hides the reason for the problem.

Newf
Feb 14, 2006
I appreciate hacky sack on a much deeper level than you.

GrumpyDoctor posted:

With that little contextual information, I think the only advice anyone can reasonably give you is "All of those options are fine, as long as whatever you do is consistent with the rest of your codebase."

Logging swear words it is, then.

A Tartan Tory
Mar 26, 2010

You call that a shotgun?!

GrumpyDoctor posted:

Too technical. I'm an executive VP who's never programmed in my life. I don't know what "array" or "loop" means. Y? M? Just use English!

(I'm not just being a stickler to be an rear end; your fogginess about how to solve the problem is directly related to your fogginess about explaining it, I promise you.)

Ah right, let me try again.

1. Pre-populate three lists with single values, base the lists on the current year and month, with every value corresponding to a specific month.
2. Use those lists of values to do a sumproduct, but to do it for every month so I can get the sumproduct for every month. (the month starts by using the next months list value, so for the first month in the first year, it would start with the values from the second month in the first year until it got to the eleventh month in the second year, the second month in the first year would use the values from the third month in the first year until the eleventh month of the second year etc etc, the eleventh month of the second year would just use it's own list numbers for that month, where any month after that would start from the eleventh month of the second year for it's sumproduct and end at the current month's values)
3. Use the sumproduct for every month generated and divide it by two list values from that month, in order to get the final value.
4. Save the final value in an another list based on the current month for future display.

Is that a little better?

A Tartan Tory fucked around with this message at 17:21 on Sep 17, 2014

Knyteguy
Jul 6, 2005

YES to love
NO to shirts


Toilet Rascal

Newf posted:

Logging swear words it is, then.

Want to do this so bad sometimes.

EssOEss
Oct 23, 2006
128-bit approved

Newf posted:

If someone calls SomeClass SomeClassInstance = SomeClass.Load(key); with an invalid key, should the method return null or throw an exception or log some swear words or what? As far as I can tell I could go either route without much headache but I'm sure that this is something that has lots of established best practices.

fake edit: Please, look inside your mercy file... File Not Found.

I would expect any static methods returning an instance of the class (essentially fancy constructors) to throw an exception on failure unless it is explicitly clear from the name that they may return nothing as a normal part of their operations. Note that the latter is entirely separate from failing and you need to make it clear what is a failure and what is a normal "nothing result" situation. Under no circumstances should an unexpected failure result in returning null.

For example, we might try to load a configuration section that may or may not be present and both are OK situations - returning null is appropriate in this case if the method explicitly expresses this. I generally prefix such methods with Try to make it obvious that maybe they won't return anything, e.g. ConfigSection.TryLoadSection(). However, if the configuration file itself is missing then TryLoadSection() must still throw an exception - this is an unexpected failure and not the scenario in which it is OK to return nothing.

In short, you should never return null for failure but if you make it very clear that a "nothing" result is a normal part of the method, you may return null.

In practice, my preference for marking such methods with a Try prefix is a rarity and most people seem to not place such a requirement. I find it very helpful for fast code comprehension, though.

Logging is a completely orthogonal concern. Signaling errors in code should not be related to the existence or non-existence of logging statements. Add logging where it might be useful but do not use it to justify cutting corners on software design.

EssOEss fucked around with this message at 18:21 on Sep 17, 2014

Bognar
Aug 4, 2011

I am the queen of France
Hot Rope Guy

EssOEss posted:

For example, we might try to load a configuration section that may or may not be present and both are OK situations - returning null is appropriate in this case if the method explicitly expresses this. I generally prefix such methods with Try to make it obvious that maybe they won't return anything, e.g. ConfigSection.TryLoadSection(). However, if the configuration file itself is missing then TryLoadSection() must still throw an exception - this is an unexpected failure and not the scenario in which it is OK to return nothing.

A Try method that throws an exception is just asking for confusion. If you name something Try[whatever] you should match the .NET framework pattern of bool TryGetWhatever(object parameters, out object output).

EDIT: To answer the original question, throw Exceptions on exceptional cases. Is it expected that the Load method could fail in normal operation? Could you realistically do something about it if it did fail? If so, return null or some other error descriptor. Does failing to load only happen in exceptional cases (e.g. file not found, couldn't connect to server, etc.)? Throw an exception.

Bognar fucked around with this message at 22:27 on Sep 17, 2014

gariig
Dec 31, 2004
Beaten into submission by my fiance
Pillbug

A Tartan Tory posted:

Ah right, let me try again.

1. Pre-populate three lists with single values, base the lists on the current year and month, with every value corresponding to a specific month.
2. Use those lists of values to do a sumproduct, but to do it for every month so I can get the sumproduct for every month. (the month starts by using the next months list value, so for the first month in the first year, it would start with the values from the second month in the first year until it got to the eleventh month in the second year, the second month in the first year would use the values from the third month in the first year until the eleventh month of the second year etc etc, the eleventh month of the second year would just use it's own list numbers for that month, where any month after that would start from the eleventh month of the second year for it's sumproduct and end at the current month's values)
3. Use the sumproduct for every month generated and divide it by two list values from that month, in order to get the final value.
4. Save the final value in an another list based on the current month for future display.

Is that a little better?

No, I still don't understand what you are trying to do. Pretend I don't know what you are trying to calculate and describe the process. Also, add a couple of small examples of input and output. Maybe even the manual steps to get your input to be output

raminasi
Jan 25, 2005

a last drink with no ice

A Tartan Tory posted:

Ah right, let me try again.

1. Pre-populate three lists with single values, base the lists on the current year and month, with every value corresponding to a specific month.
2. Use those lists of values to do a sumproduct, but to do it for every month so I can get the sumproduct for every month. (the month starts by using the next months list value, so for the first month in the first year, it would start with the values from the second month in the first year until it got to the eleventh month in the second year, the second month in the first year would use the values from the third month in the first year until the eleventh month of the second year etc etc, the eleventh month of the second year would just use it's own list numbers for that month, where any month after that would start from the eleventh month of the second year for it's sumproduct and end at the current month's values)
3. Use the sumproduct for every month generated and divide it by two list values from that month, in order to get the final value.
4. Save the final value in an another list based on the current month for future display.

Is that a little better?

Ok, I stared at this for ten minutes and tried to make some sense of it. Tell me if this is right:

You've got three lists of values: M, N, and R. Each list has X values, and each value corresponds to data for a particular month x. You want to create a new list of values P, and then create a second list of values Q such that Q(x) = P(x) / ((N(x) * R(x)). Q is your output. The trouble you're having is with generating P. The tricky bit is that the way to calculate P(x) changes depending on x; if x < 23, you do one thing, and otherwise you do a different thing. If x < 23, then P(x) = SUMPRODUCT(M[x+1 to 23], N[x+1 to 23], R[x+1 to 23]), and if x >= 23, then P(x) = SUMPRODUCT(M[23 to x], N[23 to x], R[23 to x]).

Bognar
Aug 4, 2011

I am the queen of France
Hot Rope Guy
This sounds like something that can be solved with a few beautiful lines of LINQ, but the hardest part is going to be understanding what the hell is going on.

A Tartan Tory
Mar 26, 2010

You call that a shotgun?!

gariig posted:

No, I still don't understand what you are trying to do. Pretend I don't know what you are trying to calculate and describe the process. Also, add a couple of small examples of input and output. Maybe even the manual steps to get your input to be output

I think this might be better if I present the excel problem visually from how I usually do this calculation.

GrumpyDoctor posted:

Ok, I stared at this for ten minutes and tried to make some sense of it. Tell me if this is right:

You've got three lists of values: M, N, and R. Each list has X values, and each value corresponds to data for a particular month x. You want to create a new list of values P, and then create a second list of values Q such that Q(x) = P(x) / ((N(x) * R(x)). Q is your output. The trouble you're having is with generating P. The tricky bit is that the way to calculate P(x) changes depending on x; if x < 23, you do one thing, and otherwise you do a different thing. If x < 23, then P(x) = SUMPRODUCT(M[x+1 to 23], N[x+1 to 23], R[x+1 to 23]), and if x >= 23, then P(x) = SUMPRODUCT(M[23 to x], N[23 to x], R[23 to x]).

This is basically pretty much what I want to do. Although it is (P(x) / (N(x)) / R(x) to get the value of Q.

I'm hoping these screenshots make it a little easier to understand exactly what the calculation is doing (note all the values are changed to dummy values, obviously can't give out real stuff).



This is the calculation on the first year of the first month. The blue, red and purple columns have already been pre-generated (as either a single or 2 dimensional array, I have them in both for practice) with the correct data for every month of every year needed, so has the current months data in the light green and pink entries. It's just a matter of accessing it so I can populate the SR array with the final values.



This is the calculation on the first month of the second year, this time it uses less values in the sumproduct calculation, as it is getting closer to the end of the second year.



Calculation when it reaches the changeover to start at line 37.



Calculation after it has passed line 37, note how it now *starts* there for the sumproduct calculation and ends at the current month + 1.

So basically, what I need to do, is work out the sumproduct of the blue red and purple columns every month, and use the sumproduct by dividing by the current months green and then pink values.

Hope this helps a bit in the understanding part, I thought pictures would describe it better than I could.

A Tartan Tory fucked around with this message at 10:05 on Sep 18, 2014

Newf
Feb 14, 2006
I appreciate hacky sack on a much deeper level than you.
I've just come across something I don't understand.

C# code:
// Settings.Default.Properties is a System.Configuration.SettingsPropertyCollection

foreach(var setting in Settings.Default.Properties)
{
  // setting is an 'object'
}

foreach(System.Configuration.SettingsProperty setting in Settings.Default.Properties)
{
  // setting is a SettingsProperty
}
To the best of my knowledge, the compiler / visual studio should always know the correct type of variables declared with var. Eg, Intellisense knows anywhere in a file file that var variable = "asdf"; is a string.

What gives?

zokie
Feb 13, 2006

Out of many, Sweden
It has to be the fully qualified type names or missing usings. Does it work with just foreach(SettingsProperty p in ...)?

Bognar
Aug 4, 2011

I am the queen of France
Hot Rope Guy

A Tartan Tory posted:

I think this might be better if I present the excel problem visually from how I usually do this calculation.

As far as I can tell, this does something close to what you wanted:

https://dotnetfiddle.net/WVUbMR

The boundary conditions are probably wrong since I still don't think I fully understand those, but I believe the general idea is correct.

New Yorp New Yorp
Jul 18, 2003

Only in Kenya.
Pillbug

Newf posted:

I've just come across something I don't understand.

C# code:
// Settings.Default.Properties is a System.Configuration.SettingsPropertyCollection

foreach(var setting in Settings.Default.Properties)
{
  // setting is an 'object'
}

foreach(System.Configuration.SettingsProperty setting in Settings.Default.Properties)
{
  // setting is a SettingsProperty
}
To the best of my knowledge, the compiler / visual studio should always know the correct type of variables declared with var. Eg, Intellisense knows anywhere in a file file that var variable = "asdf"; is a string.

What gives?

You'll see that kind of thing a lot with pre-generic collections. It implements IEnumerable, not IEnumerable<T>. Even if all of the stuff in the collection is of the same type, the compiler has no way to know that. Just put a .Cast<Type>() in there.

DataTable has the same problem. Even though its Rows are DataRows, the Rows property is a non-generic collection.

A Tartan Tory
Mar 26, 2010

You call that a shotgun?!

Bognar posted:

As far as I can tell, this does something close to what you wanted:

https://dotnetfiddle.net/WVUbMR

The boundary conditions are probably wrong since I still don't think I fully understand those, but I believe the general idea is correct.

I take it that is done in LINQ? Not overly familiar with it, but I'll take a look once I'm back at home later. Is there a way to do it with just basic loops? (edit: answering my own question after looking at it a bit further, I think I understand whats happening there, will update later if I get it to work!)

Thanks for your efforts, I really appreciate it!

A Tartan Tory fucked around with this message at 16:08 on Sep 18, 2014

Newf
Feb 14, 2006
I appreciate hacky sack on a much deeper level than you.

zokie posted:

It has to be the fully qualified type names or missing usings. Does it work with just foreach(SettingsProperty p in ...)?

If I stick in the using System.Configuration; then I can use foreach(SettingsProperty p ...), but still not var.


Ithaqua posted:

You'll see that kind of thing a lot with pre-generic collections. It implements IEnumerable, not IEnumerable<T>. Even if all of the stuff in the collection is of the same type, the compiler has no way to know that. Just put a .Cast<Type>() in there.

DataTable has the same problem. Even though its Rows are DataRows, the Rows property is a non-generic collection.

Ahh, this makes sense. But my confusion has shifted to why I'm able to declare the inner variable type at all - having just tried, I'm able to compile and run

C# code:
foreach(SomeOtherClass setting in Settings.Default.Properties)
{
  // setting is an 'object'
}
only to produce a runtime error (unable to cast object of type X to type Y) on the loop when it's discovered that the setting isn't actually a SomeOtherClass.

Isn't the whole point of strong static typed languages to avoid this sort of problem? Is this an edge case wart that was a side effect of the introduction of generics which we're happy enough to suffer? (Or an edge case that appeared after the introduction of both generics and the var keyword?)

Newf fucked around with this message at 16:36 on Sep 18, 2014

raminasi
Jan 25, 2005

a last drink with no ice

Newf posted:

Isn't the whole point of strong static typed languages to avoid this sort of problem? Is this an edge case wart that was a side effect of the introduction of generics which we're happy enough to suffer? (Or an edge case that appeared after the introduction of both generics and the var keyword?)

This is the problem that generics solved, but the collection you're iterating over doesn't have a generic interface, which is why var's type inference isn't working.

Sedro
Dec 31, 2008

Newf posted:

C# code:
foreach(System.Configuration.SettingsProperty setting in Settings.Default.Properties)
{
  // setting is a SettingsProperty
}
...
Isn't the whole point of strong static typed languages to avoid this sort of problem? Is this an edge case wart that was a side effect of the introduction of generics which we're happy enough to suffer? (Or an edge case that appeared after the introduction of both generics and the var keyword?)
The loop unsafely casts each item from object to System.Configuration.SettingsProperty. It dates back to C# before generics. Compare to looping in Java 1.4 which existed around the same time.
Java code:
while (iter.hasNext()) {
  SettingsProperty = (SettingsProperty)iter.next();
}
They couldn't exactly remove the feature from the language once generics were introduced.

Newf
Feb 14, 2006
I appreciate hacky sack on a much deeper level than you.

GrumpyDoctor posted:

This is the problem that generics solved, but the collection you're iterating over doesn't have a generic interface, which is why var's type inference isn't working.

I get that, but I don't get why I'm able to declare the type of a variable when the compiler doesn't know it ahead of time. It feels like a stricter version would force me to expect only objects from an IEnumerable and then cast them myself - at least in this case the cast becomes explicit. Had I gone with foreach(SettingsProperty ... instead of var in the first place I would never have noticed that any cast was taking place - that's bad, isn't it?

Adbot
ADBOT LOVES YOU

raminasi
Jan 25, 2005

a last drink with no ice
http://stackoverflow.com/questions/3917129/foreachderived-obj-in-new-listbase is your exact question with the answer (tldr it's a special thing that foreach does for historial reasons)

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply