- Feature Articles
- CodeSOD
- Error'd
- Forums
-
Other Articles
- Random Article
- Other Series
- Alex's Soapbox
- Announcements
- Best of…
- Best of Email
- Best of the Sidebar
- Bring Your Own Code
- Coded Smorgasbord
- Mandatory Fun Day
- Off Topic
- Representative Line
- News Roundup
- Editor's Soapbox
- Software on the Rocks
- Souvenir Potpourri
- Sponsor Post
- Tales from the Interview
- The Daily WTF: Live
- Virtudyne
Admin
It's certainly a WTF, and no, it's not clear code.
Admin
[[Frist, 0, 0], [0, Frist, 0], [0, 0, Frist]]
Admin
I don't understand the specification. An example where n=4, but n is still used in the example?
Admin
Hmmm.. the "case 1" and "case n" parts could go before or after the loop, and the loop would be from 2 to n-1. So no, in this case (pun wasn't intended, but is now) it's not necessary, but could be otherwise.
Admin
The point of the for/case antipattern is that it does something completely different on each iteration. It isn't simply "any case statement inside a loop", and anyone who thinks that's inherently bad without further context needs their head examined.
Admin
As above, this is surely not a WTF.
The "worse" challenge is too easy. Anything can be implemented badly given a choice of language and limited requirements!
I suspect TRWTF is the reason for these requirements - whatever's using the output should probably have the logic in it - but we'll never know.
Admin
Okay, now how to do it better (python with numpy):
import numpy as np
n = 4
e_1 = np.zeros(n) e_1[0] = 1
e_n = np.zeros(n) e_n[n-1] = 1
n_1 = np.identity(n)[:, 1:]
n_n = np.identity(n)[:, :-1]
Admin
stupid formatting, now with line breaks:
import numpy as np
n = 4
e_1 = np.zeros(n)
e_1[0] = 1
e_n = np.zeros(n)
e_n[n-1] = 1
n_1 = np.identity(n)[:, 1:]
n_n = np.identity(n)[:, :-1]
Admin
I don't know the exact syntax, but you can simply unroll the for-case-loop and be happy:
instead of:
you can do:
there, better. The same thing. People are just weirdly afraid of for-loops counting from 2 to n-1 instead of from 1 to n. There is nothing wrong with counting from 2 to n-1.
Admin
You can actually even replace the somewhat cumbersome n_1 = np.identity(n)[:, 1:] n_n = np.identity(n)[:, :-1] with n_1 = np.eye(n, n-1, -1) n_n = np.eye(n, n-1)
in python with numpy. If you do matrix math, just use a proper library with batteries included.
Admin
You only need two lines of code with no for loop to take care of the two smaller arrays. From there the problem is simplified to a single small for loop with no switch/select.
Public Sub DefineProjectionArrays(ByVal n As Long, ByRef e_1 As Variant, ByRef e_n As Variant, ByRef n_1 As Variant, ByRef n_n As Variant) Dim i As Long, j As Long
End Sub
Admin
Uh, that 2 to n-1 idea is exactly what I wrote.
Admin
TRWTF is that if your going to be using matrix math, you should be using a tool designed specifically for matrix math. Like Matlab. Sure, you can do a lot of Engineering with Excel, but use the proper tool for the job please.
Addendum 2017-05-10 08:36: *you're. damnit.
Admin
def f(n): return (lambda x,y: ([1]+x,x+[1],[[0]*n]+y,y+[[0]n]))([0](n-1),[[int(x==y) for x in range(n)] for y in range(n)])
much clearerAdmin
addendum: the comment formatter made *'s into emphasis /inside/ a code tag. there should be a manual for commenting here ...
Admin
Yes, there should. Maybe markdown syntax will do the trick? Let's try...
Everything Is A Python Oneliner:
e_1,n_1,e_n,n_n=[map(lambda x:map(int,x[slice(*s)]),[str(10**n+10**i)[1:] for i in reversed(range(n))]) for s in ([-1,None],[1,None],[None,1],[None,-1])]
Admin
MATLAB:
Admin
Another Matlab way is to
n_n=flipud(fliplr(n_1))
Admin
If you know you want 4 arrays filled with the specified values, why bother generating it?
Why not just statically declare them?
WTF?
Admin
Like. Same idea I had.
Admin
Because the sizes are dynamic. n is passed in as a parameter.
Admin
Agree, this is trying to solve a non-problem. Just type out the definition fucking try hards. Probably has fastest computation speed too.
Admin
What I see as the quintessential for-case antipattern is:
select case i
In this case, the fact case else contains a significant amount of code (compared to the rest of the block) and uses the iteration variable means it's not for-case.
Admin
Ah...missed that...thanks :)
Quite frankly, I'm not recoiling in horror from the original code. Seems legit.
Admin
That was certainly my first thought, Dan... why the hell do you need a loop to deal with the one value in each of the single-dimension arrays?
Your code is what I would have written, and seems more intuitive to me as a result.
I did wonder why the smaller arrays couldn't just point to the appropriate column (or row) of the square arrays, though...
Admin
Watch out for overshooting the end of that array ;)
Admin
I kinda prefer a threesome of arrays. A little easier to populate...
Admin
I'm with the guys who point out that the real problem with the solution isn't the "anti-pattern:" it's a failure to understand the abstractions involved. (Which can often lead to an anti-pattern, I suppose.)
The first thing I thought when I saw the "documenting comment" was, oh boy, I wonder what the requirement is. I mean, there must be some reason to need these data structures. And there's every reason to believe that they are part of a bigger requirement, which may not yet be obvious, but will no doubt develop in time.
The second thing I thought was "Oh, look, it's sort of an identity matrix, except it isn't quite." This leads to the numpy solution given above, because the clearest and most maintainable solution is to create an identity matrix of the appropriate dimension and then to use matrix manipulation to produce the desired result. That way you are operating on actual matrixes, not on some arbitrary loop of ones and zeros.
The slight problem with using either numpy or Matlab is that, well, this is a VB.Net environment, so those don't really help that much. However, if you google/stack-overflow for .NET matrix libraries, you should be able to find a reasonable fit. (I found several.)
Admin
I desperately want to show some APL but I've not used it for 30 years.
Admin
Taken your comment to the logical conclusion then is not to create the matrix directly but in say, MATLAB, build the matrix with
maketform('projective',...)
orfitgeotrans
or whatever, in which case the matrix is treated as an opaque operator. I find that a lot of programmers, versus engineers and scientists, have a knee-jerk reaction against this level of abstraction, in part because it requires a specialized environment that has as many of the tools you need as possible, Matlab or SciPy. But also because of the large level of disconnect between what they perceive as programming. (For example, Matlab matrices are not arrays, they're complex copy-on-write structures that are completely opaque but make a lot of operations, like transposing, O(1)). Ultimately, though it is the right tool for the majority of engineering-heavy small-scale problems.Admin
I'd put it more simply in this case. 99% of programmers are not comfortable with matrix arithmetic. (I'm not particularly comfortable, for example.)
But my basic point is, if you are working in a domain where matrix transformations apply, then you are doing everybody else a disservice by not using matrix arithmetic in some way.
I mean, let's assume the product or project behind this thing uses eigenvectors or linear algorithms or any number of other things that are based upon matrix transforms. And let's assume that there are five or ten VB.Net programmers out there, each charged with a sub-task involving the implementation of one small part of what is essentially one, properly abstracted to the correct level, domain.
It isn't actually important that this one is an anti-pattern that obfuscates the abstractions inherent in the domain. It's important that there are five or ten other VB.Net programmers (in this case, the language is irrelevant) who are going to come up with five or ten completely separate and incompatible anti-patterns.
This is why I despise "clean code" freaks. Don't tackle the problem at the lowest level possible. Tackle it at the appropriate level, which is probably design and possible even architecture.
Rant over.
Admin
For "linear algorithms" please read "linear algebra." Sorry 'bout that.
Admin
You just need to create a nxn identity matrix and slice it properly... like, in python (I don't know VBA, but this shouldn't be that hard...):
tmp = numpy.identity(n)
e_1 = tmp[:,0] e_n = tmp[:,n-1] n_1 = tmp[:,1:n-1] n_n = tmp[:,0:n-2]
Admin
I'm not sure that this counts an example of the "for-case" antipattern. That antipattern usually implies that the loop has a fixed (small) number of iterations, and it does not save any effort at all, i.e. that you could fully unroll the loop and have the code be no more verbose than before. In other words, my understanding of the "for-case" antipattern is that it's only applicable for problems where a loop is unnecessary in the first place. That said, I can't remember the last time where a "for-case" was useful for anything other than processing some stream of data coming in from outside the process (e.g. event handlers, simple command line option parsing).
Anyway, I'm not really sure what the reason is for interleaving the definitions of the different variables in this example. I've hardly used any form of Visual Basic (and when I did it was over a decade ago), but aside from possible syntax errors, my "better" answer would have been something like the below. (The comments assume that these arrays are matrices for some linear algebra problem, which seems like a reasonable guess based on the function name, and the pattern mentioned in the comments.)
The only duplication here is due to using two for loops, which you could easily combine if that really bothered you enough.
Admin
e_1 = NewArray( n, 1, 0# ): e_n = NewArray( n, 1, 0# )
n_1 = NewArray( n, n-1, 0# ): n_n = NewArray( n, n-1, 0# )
e_1( 1, 1 ) = 1#
e_n( n, 1 ) = 1#
For i = 1 To ( n - 1 )
Next i
Seriously. I also sent this in via the link with my stuff attached just in case I win, but this is why that is a bad pattern. TRWTFs: Doing things in loops that need to be done exactly once, Doing what is clearly going to be Matrix Math without a matrix library, thinking that there isn't a better solution, using variables to reference things that will never move (See their method for e_n using (i , 1) instead of just (1,1)),
Anything that can be done with For-Case can be done in other, better ways. There are times when it get shoehorned into an existing system because it's easy as heck to add and relatively easy to understand, but that doesn't make it good. If I'd been asked to review this code and it was in production, I would likely not have given more than a sideways glance. It isn't the worst anti-pattern in this case, but it is NOT good.
Admin
Site admin definitely needs to upgrade the Captcha - too many adbot intrusions.
Admin
Yeah, adbots with hernias, no less. (Check the domains in the links.)
Admin
That was fun:
[code] /* allocate all 0's / arr = calloc(nn-1, sizeof(int));
/* set appropriate elements to 1 / for(int i=1; i<n; i++){ arr[in-1] = 1; }
/* set the variables */ e_1 = n_n = &arr[n-1]; e_n = n_1 = &arr[0]; [\code]
Pure evil, but It Works! The best part is that it looks like it might be reasonable (and the author would crap on any objections because it's "so creative and elegant").
Admin
I was working in PHP today, so thought I'd do a little practice.
My rough, quick answer: function DefineProjectionArrays($n, &$e_1, &$e_n, &$n_1, &$n_n) { if ($n < 2) { return; } $e_1 = $e_n = array_fill(0, $n, array_fill(0, 1, 0)); $n_1 = $n_n = array_fill(0, $n, array_fill(0, $n - 1, 0));
}
And some creatively worse solutions: function DefineWorseProjectionArrays($n, &$e_1, &$e_n, &$n_1, &$n_n) { $e_1 = $e_n = $n_1 = $n_n = array();
}
function DefineEvenWorseProjectionArrays($n, &$e_1, &$e_n, &$n_1, &$n_n) { $e_1 = $e_n = $n_1 = $n_n = array();
}
Admin
The real WTF is that this code fails for n = 1. If my mental VB interpreter is correct, this code returns [1], [0], [[]], [[]] instead of [1], [1], [[]], [[]].
Admin
I like the fact that this example is written in an old enough version of VB to preclude the option of declaring 4 arrays with initializers. These arrays are small enough that they don't really need code to initialize them.
Admin
Nowhere near Pythonic enough. Plus, e_1 and e_n are supposed to be two-dimensional. You want this:
Admin
Obfuscation level 2 (level 1 is the original WTF)
Public Sub DefineProjectionArrays(ByVal n As Long, ByRef e_1 As Variant, ByRef e_n As Variant, ByRef n_1 As Variant, ByRef n_n As Variant) Dim i As Long, j As Long, k as Long
End Sub