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
Sedro
Dec 31, 2008

Combat Pretzel posted:

Those Telerik guys must have a really hard time to get by. A long while ago, I've downloaded one of their UI component libraries to get a very old project up and running to check out some things. Since then, some sales guy is pestering me with at least one e-mail per week.

I bought some Telerik stuff and they're still trying to sell it to me

Adbot
ADBOT LOVES YOU

Xik
Mar 10, 2011

Dinosaur Gum
"Telerik" is a dirty word for every .NET developer I have met. I've literally never heard anyone say anything positive about their products.

The only exposure I've personally had to their products is a lovely WYSIWYG editor in some old version of DNN...

EssOEss
Oct 23, 2006
128-bit approved
I found their UI toolkit quite well-featured back in 2006, well worth the cost. No idea how they have evolved since then, though, or what the competition is like these days.

NihilCredo
Jun 6, 2011

iram omni possibili modo preme:
plus una illa te diffamabit, quam multæ virtutes commendabunt

We're feeling the ground in the mobile market right now and we have tasked an intern with building us a demo of their Xamarin Forms and Xamarin Native UI toolkits. They sure look sleek, but we want to figure out how useable and customisable they are.

chippy
Aug 16, 2006

OK I DON'T GET IT

Xik posted:

"Telerik" is a dirty word for every .NET developer I have met. I've literally never heard anyone say anything positive about their products.

The only exposure I've personally had to their products is a lovely WYSIWYG editor in some old version of DNN...

I'm doing a project that's a massively customised version of nopCommerce at the moment. It uses Telerik's Kendo UI controls in its admin area and they are a loving nightmare to work with. Mind you, that's partly because they chose to licence the version of the controls that have to be purely instantiated and configured using Javascript, instead of the version that has a load of nice HTML Helpers for the MVC framework.

Baby Proof
May 16, 2009

Xik posted:

"Telerik" is a dirty word for every .NET developer I have met. I've literally never heard anyone say anything positive about their products.

The only exposure I've personally had to their products is a lovely WYSIWYG editor in some old version of DNN...

Well, for one, Fiddler is pretty useful, and their decompiler seems nifty.

B-Nasty
May 25, 2005

Some Telerik tools, like the reporting library, can save massive amounts of time for lame CRUD work like outputting PDF reports, but $deity help you if you deviate from simple cases. I used the report engine a few years ago for a handful of relatively simple reports, and it wasn't long before I was downloading their source code* and extending their classes to handle scenarios it wasn't designed for.

*It's nice that they provide this option so you aren't totally hosed.

Ciaphas
Nov 20, 2005

> BEWARE, COWARD :ovr:


Anyone with experience in EF against an Oracle database who might know why a nullable number column coming into a decimal? field might cause an InvalidCastException for some rows? There's one row in particular that causes the crash reliably, where the number is 0.0000006924267etcetc. I can't change it to double? in the model because then the build complains that that's incompatible with Oracle number.

Night Shade
Jan 13, 2013

Old School

Baby Proof posted:

Well, for one, Fiddler is pretty useful, and their decompiler seems nifty.

Telerik bought Fiddler as a fully functional product and have basically just been maintaining it ever since. And I think their decompiler is based on a fork of .NET Reflector before RedGate bought it out and started charging for it.

SirViver
Oct 22, 2008

Ciaphas posted:

Anyone with experience in EF against an Oracle database who might know why a nullable number column coming into a decimal? field might cause an InvalidCastException for some rows? There's one row in particular that causes the crash reliably, where the number is 0.0000006924267etcetc. I can't change it to double? in the model because then the build complains that that's incompatible with Oracle number.
How are the number columns on your Oracle DB defined? Unless you limit both scale and precision appropriately, a .NET decimal field won't necessarily be able to hold the value Oracle provides. You can usually easily force such errors by doing something like SELECT 1/3 FROM dual - the Oracle data provider will in such cases (annoyingly, but quite rightfully) throw InvalidCastExceptions (or maybe actually OverflowExceptions, that later get masked by the invalid cast ones - yeah, don't ask, the Oracle Managed Data Provider is a truly amazing piece of engineering :downs:), as the conversion would technically make you lose data, even if in most practical cases you probably don't actually care about that loss.

Now, I have no idea how EF handles this respectively how much it allows overriding its default behavior, but from my experience working with our own DAL you sort of have three ways of dealing with this (assuming you generally don't actually care about keeping maximum possible numerical precision):
  1. Restrict the number columns to an appropriate scale+precision that fits in a .NET decimal. By default, Oracle numbers will allow storing values up to 38 digits total, while a .NET decimal can hold only up to 28. Note, however, that this won't save you if you ever do divisions in your queries. If you just do straight reads/writes this might be enough, though.
  2. Select the values ROUND()ed appropriately, assuming most troubles stem from having too many decimal places. Quick, extremely ugly and not 100% foolproof either.
  3. Intercept whatever mechanism tries to read values as decimal and read them as the Oracle data provider-native OracleNumber instead. Then perform some maths to trim the raw data down to a size that fits a .NET decimal before converting it. This has the advantage of failure-proofing your data access without requiring SQL changes, while still providing maximum precision allowed by a decimal. The downside is having to deal with the Oracle specific guts that EF is supposed to hide away from you in the first place. May not actually possible to do with EF in the first place, though... no idea :shrug:

No Safe Word
Feb 26, 2005

PSA: ILSpy is just way better than Telerik's JustDecompile and it isn't nagware

Ciaphas
Nov 20, 2005

> BEWARE, COWARD :ovr:


SirViver posted:

How are the number columns on your Oracle DB defined? Unless you limit both scale and precision appropriately, a .NET decimal field won't necessarily be able to hold the value Oracle provides. You can usually easily force such errors by doing something like SELECT 1/3 FROM dual - the Oracle data provider will in such cases (annoyingly, but quite rightfully) throw InvalidCastExceptions (or maybe actually OverflowExceptions, that later get masked by the invalid cast ones - yeah, don't ask, the Oracle Managed Data Provider is a truly amazing piece of engineering :downs:), as the conversion would technically make you lose data, even if in most practical cases you probably don't actually care about that loss.

Now, I have no idea how EF handles this respectively how much it allows overriding its default behavior, but from my experience working with our own DAL you sort of have three ways of dealing with this (assuming you generally don't actually care about keeping maximum possible numerical precision):
  1. Restrict the number columns to an appropriate scale+precision that fits in a .NET decimal. By default, Oracle numbers will allow storing values up to 38 digits total, while a .NET decimal can hold only up to 28. Note, however, that this won't save you if you ever do divisions in your queries. If you just do straight reads/writes this might be enough, though.
  2. Select the values ROUND()ed appropriately, assuming most troubles stem from having too many decimal places. Quick, extremely ugly and not 100% foolproof either.
  3. Intercept whatever mechanism tries to read values as decimal and read them as the Oracle data provider-native OracleNumber instead. Then perform some maths to trim the raw data down to a size that fits a .NET decimal before converting it. This has the advantage of failure-proofing your data access without requiring SQL changes, while still providing maximum precision allowed by a decimal. The downside is having to deal with the Oracle specific guts that EF is supposed to hide away from you in the first place. May not actually possible to do with EF in the first place, though... no idea :shrug:

Thanks for the ideas and information. I eventually figured out (just now in fact) that the problem is exactly as you say. Some of those numbers go out to 30 digits after the decimal. Until I'm told otherwise though I have to assume I need to keep all of them.

The annoying part is, I'm just turning them into XML output for this application, so if the EF modeler would just let me set the C# parameter type to string instead of decimal I'd be fine. Unfortunately it complains that string isn't compatible with Edm.number when I save the model like that.

Maybe I'll just hardcode those values in the application, it's only four rows with super precise values and "never" changes, but that's obviously terrible.

:mad:

mortarr
Apr 28, 2005

frozen meat at high speed

Xik posted:

"Telerik" is a dirty word for every .NET developer I have met. I've literally never heard anyone say anything positive about their products.

The only exposure I've personally had to their products is a lovely WYSIWYG editor in some old version of DNN...

I use their stuff for inhouse web apps, both the mvc helpers and pure js stuff in parallel with bootstrap for styling, to help with building more complex data entry forms, eg grids etc - I find it OK, but I guess if anyone who does a heap more javascript day to day than me came across my code they'd likely rip their hair out. It takes a fair bit of work sometimes but maybe I'm working against the product rather than with it. Their help is OK to good, depending the area you're looking for help in, which is better than many of toolsets I've used over the years.

That said, I'd rather have it than not, but I'd love to have a decent amount of time to really come up to speed on the more modern js tools/whaever like angular, react js, etc - maybe there's an alternative? It seems a lot of people have equivalent issues with complex ui regardless the tech, so quitting the browser/web-as-ui doesn't seem that attractive to me.

If there are other toolsets to use or ways of doing ui, I'd be keen to find out.

Uziel
Jun 28, 2004

Ask me about losing 200lbs, and becoming the Viking God of W&W.

chippy posted:

I'm doing a project that's a massively customised version of nopCommerce at the moment. It uses Telerik's Kendo UI controls in its admin area and they are a loving nightmare to work with. Mind you, that's partly because they chose to licence the version of the controls that have to be purely instantiated and configured using Javascript, instead of the version that has a load of nice HTML Helpers for the MVC framework.
Ugh, I just inherited the support and future development for an app that is entirely built on Kendo UI and not looking forward to this.

chippy
Aug 16, 2006

OK I DON'T GET IT

Uziel posted:

Ugh, I just inherited the support and future development for an app that is entirely built on Kendo UI and not looking forward to this.

To be fair, if you take the time to get to know them properly, they're could beok. They are fairly flexible/powerful, it's just the way to do things is often quite unintuitive and the documentation is not the best. I've generally found I've had to do a lot of googling around to find examples of what I need to do. It probably doesn't help that my Javascript is not as strong as my C#, I've never undertaken any in-depth learning and just picked things up piecemeal as I've needed them. A strong JS dev might think they are great for all I know!

Drastic Actions
Apr 7, 2009

FUCK YOU!
GET PUMPED!
Nap Ghost

chippy posted:

A strong JS dev might think they are great for all I know!

Nah, Typescript + React is the way I go. :shrug:

EDIT: And for charts and stuff, I go with D3 rather than these pre-built solutions. Yeah, more of a pain to use if you've never learned it and it'll probably take longer to get to the end product (something management tends to not want to hear) but the results you'll get are much better IMO.

Drastic Actions fucked around with this message at 17:07 on Nov 9, 2016

john donne
Apr 10, 2016

All suitors of all sorts themselves enthral;

So on his back lies this whale wantoning,

And in his gulf-like throat, sucks everything

That passeth near.

chippy posted:

A strong JS dev might think they are great for all I know!

Kendo is terrible. The only redeeming feature of their entire kit is that the grid comes with pre-built filter/sort options.

Mycroft Holmes
Mar 26, 2010

by Azathoth
Hey guys, I'm taking a course on visual basic 2015 and I'm kind of stumped on this assignment. Right, so I need to use a listbox to display two columns of information entered by two separate input boxes. The idea is that on button will bring up an input box in which to enter one piece of data which will display in the first column and another button will do the same only display in the second column. I need to do this while pulling the displayed data from two separate arrays each on holding one type of data. Also, how do I make it so entering a piece of data after the array is full brings up an error box to the user. Can someone please help me?

raminasi
Jan 25, 2005

a last drink with no ice

Mycroft Holmes posted:

Hey guys, I'm taking a course on visual basic 2015 and I'm kind of stumped on this assignment. Right, so I need to use a listbox to display two columns of information entered by two separate input boxes. The idea is that on button will bring up an input box in which to enter one piece of data which will display in the first column and another button will do the same only display in the second column. I need to do this while pulling the displayed data from two separate arrays each on holding one type of data. Also, how do I make it so entering a piece of data after the array is full brings up an error box to the user. Can someone please help me?

I'd be astonished if this were the very first assignment. What have you come up with your own so far? What else have you done in the course?

Mycroft Holmes
Mar 26, 2010

by Azathoth

raminasi posted:

I'd be astonished if this were the very first assignment. What have you come up with your own so far? What else have you done in the course?

It isn't. This is homework program number 5. We've just gone over arrays. Basically, this is the only stumbling block. If I get this, I can do the rest of the program no sweat, it's just some simple functions.

Bognar
Aug 4, 2011

I am the queen of France
Hot Rope Guy
I'm having a hard time getting it from your description. Could you MS Paint your way to what you think the UI should be doing here?

Mycroft Holmes
Mar 26, 2010

by Azathoth

Bognar posted:

I'm having a hard time getting it from your description. Could you MS Paint your way to what you think the UI should be doing here?

Bognar
Aug 4, 2011

I am the queen of France
Hot Rope Guy
So, a list box can't hold more than one column. You can either use two listboxes, one that represents a list of students and one that represents a list of grades, or you can use a DataGridView which would show the data in a table. If you choose to use a DataGridView, then you would need to change your buttons to add a student and a grade at the same time (adding a row to a table adds a cell to all columns at once, so you can't just add a student or add a grade).

Given that you've only worked with arrays so far, the easiest thing to do right now would be to use two listboxes. I would argue that this isn't as correct as using a table, but it's probably better for you to put something together that's easy and that works. To work with items in a listbox programmatically, use ListBox.Items.

To show a pop-up for an error message in WinForms, you can use MessageBox.Show.

Mycroft Holmes
Mar 26, 2010

by Azathoth
Alright, I can't figure out what I'm doing wrong. I'm trying to get the listbox to only display the seven items in the array. It keeps just adding items to the listbox. I can't tell if it's also adding items to the array though. What am I doing wrong?
code:
Dim intCount As Integer
        For intCount = 0 To intCount = 6
            strStudentNames(intCount) = InputBox("Input the students name", "Name Entry", "John Smith",)
            If IsNumeric(strStudentNames(intCount)) = True Then
                MsgBox("Please enter a name")
                strStudentNames(intCount) = 0
                intCount = (intCount - 1)
            ElseIf IsNumeric(strStudentNames(intCount)) = False Then
                lstNames.Items.Add(strStudentNames(intCount))
            End If
        Next

Mycroft Holmes
Mar 26, 2010

by Azathoth
Ok, wow, none of my other code is working either.
code:
    Dim intMax As Integer = 6
    Dim strStudentNames(intMax) As String
    Dim intScores(intMax) As Double

    Private Sub btnStudent_Click(sender As Object, e As EventArgs) Handles btnStudent.Click
        Dim intCount As Integer
        For intCount = 0 To intCount = 6
            strStudentNames(intCount) = InputBox("Input the students name", "Name Entry", "John Smith",)
            If IsNumeric(strStudentNames(intCount)) = True Then
                MsgBox("Please enter a name")
                strStudentNames(intCount) = 0
                intCount = (intCount - 1)
            ElseIf IsNumeric(strStudentNames(intCount)) = False Then
                lstNames.Items.Add(strStudentNames(intCount))
            End If
        Next
    End Sub

    Private Sub btnGrade_Click(sender As Object, e As EventArgs) Handles btnGrade.Click
        Dim intCount As Integer
        For intCount = 0 To intCount = 6
            intScores(intCount) = InputBox("Input the students grade. Grades shold be between 0 and 100.", "Grade Entry")
            If IsNumeric(intScores(intCount)) <> True Then
                MsgBox("Please enter a number")
                intScores(intCount) = 0
                intCount = (intCount - 1)
            ElseIf intScores(intCount) > 100 Then
                MsgBox("Please enter a number equal to or under 100")
                intScores(intCount) = 0
                intCount = (intCount - 1)
            ElseIf intScores(intCount) < 0 Then
                MsgBox("Please enter a number equal to or under 100")
                intScores(intCount) = 0
                intCount = (intCount - 1)
            ElseIf IsNumeric(intScores(intCount)) = True Then
                lstGrades.Items.Add(intScores(intCount))
            End If
        Next
    End Sub

    Private Sub btnAverage_Click(sender As Object, e As EventArgs) Handles btnAverage.Click
        Dim dblTotal As Double
        Dim dblAverage As Double
        Dim intCount As Integer
        For intCount = 0 To 6
            dblTotal += intScores(intCount)
        Next
        dblAverage = dblTotal / 7
    End Sub

    Private Sub btnRange_Click(sender As Object, e As EventArgs) Handles btnRange.Click
        Dim intCount As Integer
        Dim dblHighest As Integer
        Dim dblLowest As Integer
        dblHighest = intScores(0)
        For intCount = 1 To intCount = 6
            If intScores(intCount) > dblHighest Then
                dblHighest = intScores(intCount)
            End If
        Next
        dblLowest = intScores(0)
        For intCount = 1 To intCount = 6
            If intScores(intCount) > dblLowest Then
                dblLowest = intScores(intCount)
            End If
        Next
        MsgBox("The range is" & (dblHighest - dblLowest),, "Results")
    End Sub

    Private Sub btnMedian_Click(sender As Object, e As EventArgs) Handles btnMedian.Click
        Array.Sort(intScores)
        Dim intItems As Integer = intScores.Length
        Dim intPosition As Integer = ((intScores.Length + 1) / 2) - 1
        Dim intValue As Integer = intScores(intPosition)
        MsgBox("The median is" & intValue,, "Results")
    End Sub

    Private Sub btnPassing_Click(sender As Object, e As EventArgs) Handles btnPassing.Click
        Dim intCount As Integer
        Dim intPassing As Integer
        For intCount = 0 To intCount = 6
            If intScores(intCount) >= 75 Then
                intPassing += 1
            End If
        Next
        MsgBox("The number of passing grades is" & intPassing,, "Results")
    End Sub

    Private Sub btnFindStudent_Click(sender As Object, e As EventArgs) Handles btnFindStudent.Click
        Dim strSearch As String = txtName.Text
        For Each strName As String In strStudentNames
            If strName.Contains(strSearch) Then
                MsgBox("Name found!")
            End If
        Next
    End Sub

    Private Sub btnClear_Click(sender As Object, e As EventArgs) Handles btnClear.Click
        Erase intScores, strStudentNames
        lstGrades.Items.Clear()
        lstNames.Items.Clear()
    End Sub

    Private Sub btnExit_Click(sender As Object, e As EventArgs) Handles btnExit.Click
        Me.Close()
    End Sub
End Class

Bognar
Aug 4, 2011

I am the queen of France
Hot Rope Guy
The way you've got the code structured right now, you need to clear lstNames at the beginning of btnStudent_Click and clear lstGrades at the beginning of btnGrade_Click. As it is now, you're just continually adding values to the ListBox each time you click the add student/grade buttons.

Mycroft Holmes
Mar 26, 2010

by Azathoth

Bognar posted:

The way you've got the code structured right now, you need to clear lstNames at the beginning of btnStudent_Click and clear lstGrades at the beginning of btnGrade_Click. As it is now, you're just continually adding values to the ListBox each time you click the add student/grade buttons.

nope. That clears the list box of all entries instead of displaying the entire array.

Bognar
Aug 4, 2011

I am the queen of France
Hot Rope Guy
I don't use VB too often so I'm not great with the syntax, but I think your for loop should be changed from:

Visual Basic .NET code:
For intCount = 0 To intCount = 6
to:

Visual Basic .NET code:
For intCount = 0 To 6

Mycroft Holmes
Mar 26, 2010

by Azathoth

Bognar posted:

I don't use VB too often so I'm not great with the syntax, but I think your for loop should be changed from:

Visual Basic .NET code:
For intCount = 0 To intCount = 6
to:

Visual Basic .NET code:
For intCount = 0 To 6

That fixed just about everything. Just one last issue. I keep getting an error whenever I try to get the error codes working. When I input grades using
code:
intScores(intCount) = InputBox("Input the students grade. Grades shold be between 0 and 100.", "Grade Entry")
, I get an error where the whole program stops when I input a letter instead of a number. What needs to happen is the program itself shows an error box saying to input a number. What happens is the program pulls up the coed and gives me a conversion error saying "An unhandled exception of type 'System.InvalidCastException' occurred in Microsoft.VisualBasic.dll

Additional information: Conversion from string "f" to type 'Integer' is not valid."

Bognar
Aug 4, 2011

I am the queen of France
Hot Rope Guy
You're trying to store a string value into an int array. VB is trying to automatically perform that conversion, but it fails when it's unable to (i.e. when you enter a letter). What you could do is store the value from the InputBox in a temporary variable, check if it is numeric, then assign it to the array if it is.

Visual Basic .NET code:
Dim input As String = InputBox("Input the students grade. Grades shold be between 0 and 100.", "Grade Entry")
If IsNumeric(input) Then
    intScores(intCount) = input
Else
    // handle invalid input
End If

Bognar fucked around with this message at 04:44 on Nov 11, 2016

raminasi
Jan 25, 2005

a last drink with no ice

Bognar posted:

I don't use VB too often so I'm not great with the syntax, but I think your for loop should be changed from:

Visual Basic .NET code:
For intCount = 0 To intCount = 6
to:

Visual Basic .NET code:
For intCount = 0 To 6

I always thought C# and VB.NET were different skins on the same model. What the hell is this about? Why does the first one even compile, and what does it actually do?

ljw1004
Jan 18, 2005

rum

raminasi posted:

code:
Dim x As Integer
For x = 0 To x = 16
I always thought C# and VB.NET were different skins on the same model. What the hell is this about? Why does the first one even compile, and what does it actually do?

First, how does the expression even parse? ...

code:
For x = 0 to x = 16
// "x = 16" is an expression, the same as "x == 16" in C#. So this evaluates to:

For x = 0 to False
Second, what do the identifiers bind to?

code:
Dim x As Integer
For x = 0 to 15
// Here the variable "x" already exists, so it binds to it, like C# "int x; for (x=0; x<15; x++)"

For y = 0 to 15
// Here the variable "y" doesn't pre-exist, so this declares a new one, like C# "for (int x=0; x<15; x++)"
Third, what are the types? VB requires an implicit conversion from the lower and upper bounds to the type of the loop control variable. VB by default is a loosely typed language, like JS or PHP. (Interestingly, VB has XML literals in it, just like JS does if you use React/JSX, and just like PHP does if you use Hack/XHP). I don't have access to a VB compiler right now but I assume that "False" implicit converts to the number 0 in non-strict mode, or is a compile-time error in strict mode.

code:
For x = 0 to False
// I suspect equivalent to C# "for (int x = 0; x<0; x++)"

uvar
Jul 25, 2011

Avoid breathing
radioactive dust.
College Slice

raminasi posted:

I always thought C# and VB.NET were different skins on the same model. What the hell is this about? Why does the first one even compile, and what does it actually do?

From a quick experiment (and not remembering much of VB either, thank god, but which means I might be wrong), it makes sense once I remembered VB's equality operator is just the single = sign.

In this case, the for loop runs from "0 to False", which is equivalent to "0 to 0", so it runs once with the initial value. Fun aside: because VB's true is usually equivalent to -1, this loop is skipped entirely:
code:
For intCount = 0 to intCount = 0
e: dang, shouldn't have got distracted with VB's Boolean weirdness.

EssOEss
Oct 23, 2006
128-bit approved
And I thought VB was just silly C# with many words! This is fascinating! I would love to hear more about VB.Net!

NihilCredo
Jun 6, 2011

iram omni possibili modo preme:
plus una illa te diffamabit, quam multæ virtutes commendabunt

EssOEss posted:

And I thought VB was just silly C# with many words! This is fascinating! I would love to hear more about VB.Net!

Here's some trivia in no specific order


  • VB's static classes are called modules, and they have a single big difference: they are automatically imported into the parent namespace by default. While originally meant to reduce verbosity, particularly when writing small utility modules, In most projects this leads to horrible, horrible namespace pollution, especially since the project system actively encourages the user to import all the namespaces all the time. (Whenever you add a reference in Visual Studio, you can just check a box to automatically import its namespace into every file in your project. Gross.)

    Fortunately, the solution is trivial: simply wrap every module in a namespace; I like to name such wrapped modules __ in order to shorten tooltips. In light of that, you could argue that this is actually better than the C# system, since even though the defaut behaviour is very poor you do have a choice whether to auto-import the module or not. (IMO the best system, unsurprisingly, is F#'s where modules are not imported but you can simply add an attribute to make them so).

  • Empty parentheses () when calling a method are optional in VB. This means that the syntax is identical for accessing a field, accessing a parameterless property, and accessing a parameterless member function.

    However, VB.net has first-class functions, and those really really don't play well with optional parenthesis: if I write Dim foo = MyClass.MyFunction, is foo the result or a reference to the function itself? 99% of the time it will be the former, but there's no way to distinguish the two if you want to let the user enjoy type inference (and boy does type inference kick rear end). Hence the awkward AddressOf operator, which tells the compiler that you want to treat the following function as a first-class value.

    But that's not all. What about lambdas, as in Dim foo = Function(x) x * 2? Well, the VB team seems to have decided that since lambdas definitely didn't exist in Classic VB, they could afford to give them a more C-like design. So there is no AddressOf operator required, but parentheses are required when invoking a lambda.

  • Speaking of lambdas, did you know that you can yield from a lambda in VB.Net, which you cannot do in C#? You do however have to declare the lambda as "iterator", same as you do with regular non-lambda iterator functions:
    code:
    dim foo = iterator function()
                  yield a
                  if poop then exit function
                  yield b
                  yield c
                end function
    I've never figured out why the "iterator" declaration is required, since the use of "yield" ought to be enough to identify the method as an iterator. I hope Lucian will chime in on this, and I fear the answer may involve the words "option strict off".

  • Every function in VB.Net comes with a complimentary, uninitialised, implicit return variable, with the same name as the function itself. See the "Exit Function" I used in the iterator snippet above? Well, if you use it in a regular, non-iterator function, it will actually return whatever's stored in the return variable. The same will happen if you reach the end of the function without having hit an explicit "Return <whatever>" statement. Quite useful, especially when you're returning a POCO whose properties you gradually set throughot your function.

  • Actually, you can "exit" out of pretty much anything in VB.Net, not just Exit Function / Sub:
    - Exit For / Exit Do / Exit While are like c# break, but if you have nested loops you can break out of the outer one with a single statement - but only if the loops are of different types, which is super weird
    - Exit Select is like the break in a c# switch, but it's not pointless boilerplate, you only need to use it when you actually have code you want to skip
    - Exit Try is perhaps the most interesting, since AFAIK you can't do this one in C# at all

  • This is perhaps my favourite. VB.Net has an interesting legacy keyword called 'Static'. It has nothing to do with C-like static entities (those are called "Shared"). Rather, it can be used to declare a local variable in place of the usual Dim. If you do, the value of the variable is retained between each call of the function where the static variable appears.

    In effect, what you have (and what this ultimately compiles to) is a private, thread-safe field that is scoped to a specific method. This is monstrously useful for keeping your classes lean clean, and it's a drat shame that every example of the keyword is some pointless poo poo like:

    code:
    public function Count as integer
        static countTotal as Integer = 0
        countTotal += 1
        return countTotal
    end function
    when it is far, far more interesting to do stuff like this:

    code:
    public readonly property Butt as butt
        get
             static hiddenButt as butt = SomeVeryExpensiveFunction
             return hiddenButt
        end get
    end property
    You didn't miss the thread safety, right? Courtesy of an old blog post, here is what that simple "static hiddenButt as butt = SomeVeryExpensiveFunction" line compiles to:

    code:
    Const STATE_INITIALIZED As Integer = 1
    Const STATE_INITIALIZING As Integer = 2
    Const STATE_UNINITIALIZED As Integer = 0
    
    If $STATIC$get_Butt$0118$hiddenButt$Init.State <> STATE_INITIALIZED Then
        Monitor.Enter($STATIC$DoStuff$0118$hiddenButt$Init)
        Try
            If $STATIC$get_Butt$0118$hiddenButt$Init.State = STATE_UNINITIALIZED Then
                $STATIC$get_Butt$0118$hiddenButt$Init.State = STATE_INITIALIZING
                $STATIC$get_Butt$0118$hiddenButt = SomeVeryExpensiveFunction
                Goto Continue_Code
            End If
            If $STATIC$get_Butt$0118$hiddenButt$Init.State = STATE_INITIALIZING Then
                Throw New IncompleteInitialization()
            End If
        Finally
            $STATIC$get_Butt$0118$hiddenButt$Init.State = STATE_INITIALIZED
            Monitor.Exit($STATIC$get_Butt$0118$hiddenButt$Init)
        End Try
    End If
    Continue_Code:
    So yeah. Pretty nice. And I can't check it right now, but a while ago I took a look myself at the generated MSIL in my project and I seem to remember that 2016 code to have been somewhat more refined compared to the 2003 version I quoted above.

mystes
May 31, 2006

NihilCredo posted:

This is perhaps my favourite. VB.Net has an interesting legacy keyword called 'Static'. It has nothing to do with C-like static entities (those are called "Shared"). Rather, it can be used to declare a local variable in place of the usual Dim. If you do, the value of the variable is retained between each call of the function where the static variable appears.
This is what the static keyword does in c. Also, please don't use it. You shouldn't randomly hide global state inside functions.

rarbatrol
Apr 17, 2011

Hurt//maim//kill.
One of my favorite things with VB.Net was actually the XML literals... if you ever need to work with XML, it's pretty handy.

ljw1004
Jan 18, 2005

rum

mystes posted:

This is what the static keyword does in c. Also, please don't use it. You shouldn't randomly hide global state inside functions.

Not the same as C. Look at NihilCredo's expansion. The VB static local variable is per-instance of the object -- not global.

I get that functional paradigm likes to have "Plain Old Data" classes where every single part of an object's state is declared all together up front. But (1) even in that style it's still nice to have memoization, and declaring the memoized value local to the function is cleaner. And (2) if you're in a more object-oriented paradigm and you declare state interspersed amongst methods, then static variables no worse.


NihilCredo posted:

I've never figured out why the "iterator" declaration is required, since the use of "yield" ought to be enough to identify the method as an iterator.

Imagine if you have a method "Sub Yield(x%)". Then the statement "Yield (5)" would be ambiguously either an invocation of the method, or a yield statement. By sticking in the Iterator method, we remove ambiguity. (We didn't feel able to make "Yield" a new reserved keyword because it seemed too likely a field/method/local name in financial calculations...)

We had the same issue with NameOf() operator. In C# they decided to make it bind to a method called "nameof" (if one exists), and only otherwise to bind to the new nameof operator. That was to aggressively pursue 100% backwards compatibility. It came at the cost of making Roslyn syntax analyzers harder to author because nameof nodes have to be represented as invocation-expressions in the Abstract Syntax Tree. In VB we decided that the loss of 100% back-compat wasn't so severe, and so we made NameOf a reserved keyword, and we represent it as its own node in the AST. This was easier to write in the compiler, easier to colorize, and easier to write analyzers. So far no one has complained about the back-compat break :)

Other reason: I think it's fishy when the return type of the method disagrees with the type of the return statement's operand. The "Iterator" modifier feels like a bit of a disclaimer.

Other reason: We introduced async and iterator methods+lambdas to VB at the same time, so giving them both a modifier felt regular.

Other reason: We wanted to give these new kinds of methods a name that every user of the language would use when they talk about code with colleagues, or when searching on the internet. The modifier encourages that.



I should say that I'm no longer on VB! I recently moved to Facebook where I'll be working on the open-source Hack language. It's a variant of PHP which has optional typing and XML literals, so I'm feeling at home :) VB is now in the very capable hands of Anthony D. Green. Alas he doesn't post to these forums.

NihilCredo
Jun 6, 2011

iram omni possibili modo preme:
plus una illa te diffamabit, quam multæ virtutes commendabunt

Thanks for the explanation!

ljw1004 posted:

Imagine if you have a method "Sub Yield(x%)". Then the statement "Yield (5)" would be ambiguously either an invocation of the method, or a yield statement. By sticking in the Iterator method, we remove ambiguity. (We didn't feel able to make "Yield" a new reserved keyword because it seemed too likely a field/method/local name in financial calculations...)

Did you consider just copying C#'s syntax? "Yield Return (5)" wouldn't have had that ambiguity, I think.


rarbatrol posted:

One of my favorite things with VB.Net was actually the XML literals... if you ever need to work with XML, it's pretty handy.

My very first assignment at work was a big gently caress-off XML document export feature... I didn't know about XML literals and ended up literally binding AutoHotKey macros to "xw.WriteElement()" and "xw.EndElement()" :negative:

Adbot
ADBOT LOVES YOU

darthbob88
Oct 13, 2011

YOSPOS
Stupid question about testing. I've got a method that indirectly relies on pulling data from a database, like I'm testing createFart() which calls getButts() which does "using (var foo = new ButtContext()){ return foo.Butts; }". Do I still need to mock that DBContext, as on this page, and if so how the hell do I mock that internal context? Alternatively, should I just rewrite this to use Dapper or something instead?

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