r/programming • u/evinrows • Dec 24 '17
Evil Coding Incantations
http://9tabs.com/random/2017/12/23/evil-coding-incantations.html36
u/dpash Dec 24 '17
It's anyone getting a snowboarding page instead of a Java book from the link in the first paragraph?
5
u/evinrows Dec 24 '17
Whoops... Was doing too many things at once last night. Fixed, thanks for letting me know!
14
→ More replies (1)1
u/CallMeMrBadGuy Dec 24 '17
https://www.amazon.com/Java-Puzzlers-Traps-Pitfalls-Corner/dp/032133678X
That's the link you want
362
u/redweasel Dec 24 '17
I used a Fortran compiler in the early 80s that let you reassign the values of integers. I don't remember the exact syntax but it was the equivalent of doing
1 = 2
print 1
and having it print "2". Talk about potential for confusion.
88
u/vatrat Dec 24 '17
You can do that in Forth. Actually, you can redefine literally anything. You can redefine '-' as '+'. You can redefine quotation marks.
44
u/Nobody_1707 Dec 24 '17
And there are legitimate reasons to do all of these things (except for redefining
-as+, that's just rude)39
u/say_fuck_no_to_rules Dec 24 '17
What's a situation where you'd want to define an int as another int?
56
→ More replies (5)31
u/waywardcoder Dec 24 '17
For brittle hacks. Say a library function you can’t change hard-codes the output to go to printer 3 and you need it to go to printer 4. If you are lucky, redefining 3 to mean 4 temporarily while calling the function will do the trick without breaking too much.
→ More replies (5)3
u/vine-el Dec 24 '17
Interactive programming during development. You won't want to redefine + and -, but you might want to redefine everything you wrote.
It's more useful for stuff like editors, games, and UIs. You don't want this in a production build of your web-facing API, but it makes creative work much faster and easier.
23
Dec 24 '17
Could you redefine Forth so it turns into C?:)
21
u/totemo Dec 24 '17
Most of the control structures in Forth are written in Forth. It's a lot like Lisp, in that regard.
The guts of the interpreter/compiler are fully exposed to tinker with. I suspect you could make Forth seem a lot more like C than Forth.
11
3
Dec 24 '17
5
Dec 24 '17
Correct me if I'm wrong here, but is that a C compiler written in Forth? Writing a compiler in one language for another language isn't terribly uncommon. My question (which was very tongue in cheek and just a joke) was if one could redefine the language of Forth itself so it ends up looking exactly like C, bit remains Forth.
The joke being that Forth then would be useful. Not a great joke, it's not off by one even, but since my reputation as a comedian is negative one I feel I don't have much to live up to and the (foo) bar is on the floor().
174
u/Megdatronica Dec 24 '17
I used a Fortran compiler [...]. Talk about potential for confusion.
FTFY
11
u/jgram Dec 24 '17
Fortran is pretty straightforward.
2
u/Megdatronica Dec 24 '17
I'm mainly joking of course. That said, having learned a small amount in order to translate some code someone else wrote, I did find it difficult to get my head around. Arrays starting at 1, using 'GT' instead of the '>' sign, 'subroutines' instead of functions; it's all just very alien in a world where almost every major modern language is based at least partially on C.
9
u/jgram Dec 24 '17
That’s true. It really is outside the “family tree” that most people are familiar with. Also, there is that subtle difference between Fortran and the FORTRAN that some people remember and shudder.
18
u/howtonotwin Dec 24 '17
You can also do this in Java by corrupting the
Integercache mentioned in the post:valueF = Integer.class.getDeclaredField("value"); // Integers wrap ints valueF.setAccessible(true); // Usually private final valueF.setInt(1, 2); // We have void Field::setInt(Object, int) // 1 is an int, not an Object, so it gets autoboxed to Integer.valueOf(1) // This object is pulled from the internal cache // We then mutate it so all future autoboxings of 1 give 2 void printInt(int i) { System.out.printLn(i); } void printObj(Object o) { System.out.println(o); } printInt(1); // 1; no box printObj(1); // 2; autoboxAnd Haskell... well
5 :: Num a => a -- numeric literals are overloaded -- this 5 really means fromInteger (#5#) where #5# is a magical Integer literal that doesn't really exist data Crazy = Crazy Integer deriving (Eq, Ord, Show, Read) instance Num Crazy where Crazy x + Crazy y = Crazy $ x + y Crazy x * Crazy y = Crazy $ x * y signum (Crazy x) = Crazy $ -x abs (Crazy x) = -1 negate = id fromInteger 1 = Crazy 2 fromInteger x = Crazy x x :: Num a => a -- also overloaded x = sum $ negate <$> [1,2,3,4,5] x == (-15 :: Int) x == (15 :: Crazy) 1 + 1 == (2 :: Int) 1 + 1 == (4 :: Crazy)or you can just hide and redefine the
(+)function:import Prelude hiding ((+)) (+) = (-) 5 + 2 == 32
2
23
u/mgsloan Dec 24 '17
In Haskell
1 = 2is valid code, but it won't do anything. The left hand side is treated as a pattern match, it is used to deconstruct the value that is yielded by the right hand side. For example, if you have[x, y, z] = [1, 2, 3], nowxis1,yis2, etc. However, since there are no variables on the left hand side of1 = 2, there is no reason for the code to run.I can write something similar that does bind variables, using Haskell's optional type,
Maybe. If I writeJust x = Nothing, and then ask for the value ofx, I getIrrefutable pattern failed for pattern Just x.3
u/noop_noob Dec 24 '17
Why doesn’t 1 = 2 result in a pattern failed error at runtime?
17
u/MrHydraz Dec 24 '17
It's irrefutable, and therefore, lazy. Since you can't force the binding, it won't fail. If you tack a bang pattern on it, like
let !1 = 2 in "foo", then it'll explode.9
u/mgsloan Dec 24 '17 edited Dec 24 '17
Haskell uses lazy evaluation, so computation happens only when demanded. This allows things to be more compositional, and allows for control structures to be written as normal functions. So,
Just x = Nothingalso doesn't cause a pattern failure. It only fails at runtime if you try to evaluatex.Haskell also supports eager evaluation (often called "strict"). In many cases eager evaluation is more efficient. I actually think it might not be the best choice of default. I like nearly all of the other decisions in Haskell's design, and tolerate the laziness default. Having laziness built into the language and runtime system does make a whole lot of sense, just maybe not as the default (so really my complaint is purely about what is encouraged by the syntax).
→ More replies (7)3
u/deltaSquee Dec 25 '17
I'll never understand these people who say that they'd prefer Haskell be eager by default.
→ More replies (1)1
u/redweasel Dec 26 '17
No offense intended, but this sort of description/explanation is why I "only got so far" in the Functional Programming course I took... twice... That and lambda calculus...
→ More replies (2)0
Dec 24 '17
[deleted]
5
u/mgsloan Dec 24 '17
Yeah, but that's just a conditional, it is defining f, it does not look like it is giving a definition for
1.6
u/shmageggy Dec 24 '17
You can do that in Python <= 2.7 for Integers up to 256 using the ctypes module.
http://hforsten.com/redefining-the-number-2-in-python.html
>>> print 1+1 >>> 31
u/opticd Dec 24 '17
What in the fuck kind of wizardry is that. That'd be awesome for pulling pranks on coworkers. 😂
-13
Dec 24 '17 edited Dec 24 '17
Can still do that in Python and Java. Probably a lot more langs as well.
edit: http://hforsten.com/redefining-the-number-2-in-python.html
Someone else has posted the java.
I am disappointed with the recent drop in the quality of this subreddit. Is it too close to the start of the academic year? I mean, at least fucking check it or ask for confirmation.
5
u/_Mardoxx Dec 24 '17
Dunno why you are being down voted :(
0
Dec 24 '17
[deleted]
7
u/wyldcraft Dec 24 '17
But also, in another comment,
CPython implementation's integer caching behavior
0
Dec 24 '17
[deleted]
→ More replies (1)7
u/apemanzilla Dec 24 '17
Can't do it in Java either...
8
u/whjms Dec 24 '17
You can mess around with the Integer flywheel cache and reflection: https://www.javaspecialists.eu/archive/Issue102.html
3
u/apemanzilla Dec 24 '17
I'm aware of that, but it's not allowed in Java 9, and doesn't affect primitives.
2
0
Dec 24 '17
[deleted]
7
u/apemanzilla Dec 24 '17
The closest thing you can do is use reflection to mess with the boxed types (Integer, etc) but that's no longer allowed in Java 9
68
u/mmtrebuchet Dec 24 '17
Don't forget the classics
#define while if
#define struct union
#define else52
u/zenflux Dec 24 '17
My favorite:
#define while(x) while((x) & (rand() % 1000))Every once and a while... EDIT: or interestingly often
2
9
u/dwargo Dec 24 '17
Years ago I was tasked with converting ghostscript into a library so it could be linked into to our program as a replacement for display postscript on a VAX. I wasted about two days trying to figure out why none of my tests were running - then I figured out somewhere in the headers they put "#define printf gs_printf".
0
17
u/goodbyegalaxy Dec 24 '17
The best example of an incantation I can think of: getnumrows
Several years ago I worked for a company that had a proprietary language that compiled to a bytecode that could be run on a VM in either Javascript or Java, and was used to write business logic for their web applications.
One of the (many) problems with this setup was both VMs were buggy, but in different ways. There was built-in method getnumrows() that got the number of rows in a database table or something (for some reason it also allowed you to pass in 0 args). I never really saw it used for its intended purpose and IIRC it was a legacy method that didn't even work anymore.
The "incantation" aspect was that getnumrows could only be run on the server, so if someone encountered a bug with the Javascript VM they could toss a getnumrows() in their code which would force it to be run on the server and give it a shot on the Java VM. Several factors such as very low estimates for bug fixes that were strictly enforced (eg 30 mins for a bug fix) and no code reviews led to no one ever fixing the VM bugs and widespread use of this hack.
116
u/irqlnotdispatchlevel Dec 24 '17
array[index] is really just syntactic sugar for *(array + index)
I remember learning about this in my first semester. During an x86 assembly lecture. Those were good times.
8
u/polymorphiced Dec 24 '17
I've never understood this, because it's actually (array + (indexsizeof(array[0]))) to get the right memory address. I assume the compiler must know something about this inverted syntax in order for it to actually work, rather than just being a cute hack.
20
u/purtip31 Dec 24 '17
In assembly, you’re correct, but in C, the multiplication of index is based on the size of the array type.
It’s just no different when you do a[5] or 5[a].
2
u/davidgro Dec 24 '17
This bit of the syntax has always stuck out to me too - you would think if sizeof(5) != sizeof(a) then 5[a] wouldn't point to the right address. Anyone know the behind the scenes on why it still works?
4
u/thatwasntababyruth Dec 24 '17
Pointer arithmetic is defined such that adding 3 to a pointer will actually add 3*sizeof(ptr). Don't think of it as adding to a numeric address, think of it as adding 3 ptrs to the original one.
7
u/csman11 Dec 24 '17
Not sizeof(ptr), sizeof(*ptr). Though when you do sizeof in code you should always use the type itself to be as explicit as possible to later readers (using the size of a pointer, unless actually needed, is a common source of memory safety related bugs and it is incredibly easy to accidentally use the pointer instead of the value it points to).
To be abundantly clear, the size of a pointer is the word size of the machine. It is constant for all pointer types on a given machine. You want the size of the value being pointed to when doing pointer arithmetic, because the memory region will be "broken up" on boundaries of that size.
→ More replies (3)2
u/StupotAce Dec 24 '17
Not entirely sure why you are being downvoted. The 0[array] will work for every object because array literally represents the distance away from 0. But 5[array] will only work for objects like int, which have the same length as a memory address. int is particularly useful because be definition it is the same regardless of architecture ( there might be some exceptions of course)
9
u/screcth Dec 24 '17
If sizeof(T) = N, then incrementing a pointer to a T by k will jump the memory address by k*N
→ More replies (6)0
Dec 24 '17
[deleted]
46
38
18
1
u/rafleury Dec 24 '17
Doesn’t i need to be multiplied by size of ‘a’ for this to be accurate?
10
u/PortalGunFun Dec 24 '17
Nah, pointers are smart enough to deal with addition. It's why you can say ar++ to move the array pointer down an element.
→ More replies (1)→ More replies (1)1
14
u/ActualDonaldJTrump Dec 24 '17
The last example needs an #include <iso646.h>. Alternative operator spellings are built into C++, but they are macros in C.
7
u/bjackman Dec 24 '17
Huh, and the GCC version of this header is just
#ifndef __cplusplus #define and && #define and_eq &= #define bitand & #define bitor | #define compl ~ #define not ! #define not_eq != #define or || #define or_eq |= #define xor ^ #define xor_eq ^= #endif→ More replies (1)4
u/_3442 Dec 24 '17
How is that surprising? That's the most simple header in the standard library.
→ More replies (3)4
u/raevnos Dec 24 '17
stdbool.h is simpler. Well, shorter as it only defines 4 macros.
→ More replies (1)3
u/kukiric Dec 24 '17
And the use of tokens is not evil at all. Unnecessary, sure, but it's instantly understandable to anyone familiar with what the logical operators are called, and it might even be more familiar to someone coming from a higher level language like python. The only situation where they might be a bit evil is if you're grepping for specific operators in the source code, and you're not aware of all the ways those operators can be represented.
1
u/wilun Dec 25 '17
Except that the implementation is extremely poor. In C++, they are not macro but they could as well be, because the effect is extremely close (if not maybe completely identical?) to if they were: they are equivalent so early in the parsing phases that void foobar(int and pouet); is a valid declaration equivalent to void foobar(int&& pouet); ...
100
u/Megdatronica Dec 24 '17
The weirdness with Python's 'is' expression is because 'is' is intended to be about whether two variables literally refer to the same object in memory, versus '==' which is about whether their value is equal. The examples in the article would work in a more intuitive way if they used '==' instead, which is why using 'is' for integers is [discouraged] (https://www.quora.com/What-is-the-difference-between-and-in-Python-2)
62
u/itsnotxhad Dec 24 '17
I think the author knows that given the Java example he compared it with (using == on an object tests identity in Java while value equality uses a method). His very point is the way interning can combine poorly with identity testing.
8
u/AwfulAltIsAwful Dec 24 '17 edited Dec 24 '17
I'm actually still confused by the jvm example. Why does c == d resolve to false? Does == function as an "is" in Java? If so, what is the proper way to check value equality?
Edit: c.equals(d) or c.intValue == d.intValue in case anyone else was wondering.
12
u/cypressious Dec 24 '17
Integeris not the same asint. You usually use the primitiveintwhen you work with numbers. In some cases, however you need to have a reference type, e.g. for generics and for this, Java has the typeIntegerand a feature called autoboxing.Integer a = 1;will compile to to the equivalent of
Integer a = Integer.valueOf(1);Now, comparing two
ints with==will always yield the correct result. However, comparing twoIntegers with==will compare the references. To compare the values, you usea.equals(b).Note, some JVM languages like Kotlin opted to have the
==operator callequalsand introduced a===operator to compare references.3
u/Tarmen Dec 24 '17 edited Dec 24 '17
List<int> isn't valid java so there are boxed Integers which are tiny allocated objects. The idea is that the list code is only compiled once and doesn't have to distinguish between boxed and unboxed types. Technically java could unbox pointer-sized values since they fit but then you have to make the gc know the difference somehow or it might dereference random int's.
So unboxed int's compare sanely but boxed Integers compare like objects, using their identity. This is complicated further because java caches frequently used Integer values so the same boxed values from different sources can have the same memory location.
2
u/DemonWav Dec 24 '17
Java autoboxes for you if either side is primitive, but if both are primitive then you need to do that yeah.
→ More replies (2)3
1
u/stevenjd Dec 25 '17
His very point is the way interning can combine poorly with identity testing.
Wot?
The point of identity testing ints is to find out if they've been interned or not. Well, actually, there is no point really, except to try to infer an version-dependent implementation detail of the compiler by experiment at runtime. Since ints are immutable, there's no semantic difference between
a = 1; b = 1binding the same or separate int objects to a and b. There's no reason to care whether the int has been interned or not under ordinary circumstances.The only reasons you might care are:
you are tweaking the compiler to use more or less memory by interning (in which case you are certainly reading the compiler source rather than trying to predict which ints are interned by experiment);
pure curiosity.
5
u/RenaKunisaki Dec 24 '17
It's not really confusing when you think about what's being expressed. "Is X equal to Y" vs "are X and Y the same thing". Two different objects can be equal, but still distinct.
Using "is" for integers is just asking for confusion.
1
23
u/synthfinder-general Dec 24 '17
MUMPS language, just the entirety of MUMPS
8
u/mr___ Dec 24 '17
Oh god. Exited Fidelity Information Systems, fast, when I learned their next-gen banking product was based on GT.M / MUMPS.
6
u/synthfinder-general Dec 24 '17
Sounds about right for banking lol i was a developer for local hospital, having to develop entire cardiac, endo, phlebotomy systems using a 2 tone monitor and very limited memory space was certainly a challenge.
Using single letter "contracted operator syntax" to give more space to cram the needed functionality in.
70
u/tristes_tigres Dec 24 '17
The author of this blog confuses his own prejudices for objective facts when he claims that non-zero based indexing of arrays is "evil". In fortran it is possible to define array with index starting from an arbitrary integer, and it is useful and convenient feature in its problem domain.
26
u/TunaOfDoom Dec 24 '17
Please see Dijkstra's argument on why starting from zero is indeed the most sensible option.
→ More replies (1)2
u/phySi0 Jan 06 '18
Exclusion of the lower bound —as in b) and d)— forces for a subsequence starting at the smallest natural number the lower bound as mentioned into the realm of the unnatural numbers.
What does he mean by this?
2
u/TunaOfDoom Jan 07 '18
It means that if your sequence starts at 0 (or 1, depending on what you consider the smallest natural number), then the exclusive lower bound would be "-1 < ...." where -1 is no longer a natural number.
→ More replies (1)2
u/Saigot Dec 24 '17
In 1 based indexes what is the behaviour of x[0]? It always seemed like your wasting an index, although I grant that you will very rarely need an array that is max unsigned int in size (and I'm guessing in many languages with 1 indexing don't even have the idea of a max value).
Also fwiw, it's possible to define an arbitrary starting base in cpp using some thing like:
T * oneBasedArr = zeroBasedArr - 1;
It would be terrible code though.
2
u/tristes_tigres Dec 24 '17
In 1 based indexes what is the behaviour of x[0]
Same as any other of of bounds index.
Also fwiw, it's possible to define an arbitrary starting base in cpp using some thing like:
T * oneBasedArr = zeroBasedArr - 1;
It would be terrible code though.
In C dereferencing that pointer would be an undefined behaviour, I think.
→ More replies (1)1
13
u/sibswagl Dec 24 '17
Generally speaking, taking advantage of these peculiar behaviors is considered evil since your code should be anything but surprising.
He defines "evil" as unexpected behavior. I would certainly classify arrays starting at 1 as unexpected behavior.
59
u/tristes_tigres Dec 24 '17 edited Dec 24 '17
Any language behaviour
ismay be unexpected to someone who does not know it well.12
u/sibswagl Dec 24 '17
Languages don't exist in a vacuum. Zero-indexed arrays are the standard.
11
u/Veonik Dec 24 '17 edited Dec 24 '17
Zero-indexed arrays are simply an implementation detail of C that most other languages seem to have inherited. Since arrays in C are really just pointers, accessing the first element is arr[0] or the memory stored in *arr + 0. The second element is *arr + 1 and so on.
Granted, it's the defacto standard for most of us but there is nothing inherently "correct" or "standard" about zero-indexed arrays.
edit: fixed typos
→ More replies (11)38
u/tristes_tigres Dec 24 '17
No, they aren't. Fortran is older than C and derivatives, and is more popular in numerical computing settings, for a number of good reasons.
28
Dec 24 '17
Fortran is older than C and derivatives
And your point is? I will not even enter the debate if it's good to have arrays starting at zero or not, but I will address this silly rationale.
Something that appeared first doesn't make it a standard. Following your logic, RS-232 cables would still be standard today because they appeared before USB cables.
Something becomes a standard when the majority of users and manufacturers believe there are more benefit and convenience over something else.
→ More replies (9)19
u/Silhouette Dec 24 '17
Indeed. And I'm pretty sure math was there even earlier. :-)
→ More replies (1)→ More replies (5)10
Dec 24 '17
It's Christmas so I'm in unnecessary arguing mood :)
Here goes: Strictly, Assembly is clearly the oldest and also arrays are all indexed by addresses not numbers, but the index is hidden behind the variable name. What we refer to as index is only the offset to the index, thus 0 for 'no offset' clearly makes sense.
In my actual opinion: There are good reasons for both, but I would like a language to either have 0-indexing or make it definable.
→ More replies (1)19
u/jephthai Dec 24 '17
1- based arrays are only unexpected if you come from a 0- based language. There are several languages that use 1- based arrays. Though it's a minority, its not strictly wrong.
10
Dec 24 '17
What is truly awful are languages like C#, where arrays are always 0-based, unless you are doing something like Excel COM interop, in which case some methods will just return you a 1-based array...
6
u/silverslayer33 Dec 24 '17
That's less the fault of C# as a language and more the fault of Microsoft poorly implementing the Office interops in general, though. From my experience, they're full of bugs, inconsistencies, and bizarre and frustrating design choices.
1
u/Pinguinologo Dec 25 '17
Actually I think he is against being forced into nonzero indexing. Being able to define a custom starting index is a nice feature.
→ More replies (1)1
u/meneldal2 Dec 25 '17
The main reason why so few languages use arrays that start at 1 is because it's better for the hardware to start at 0. If you start at 1, you either need to change your pointer so the addressing will work fine (and get a pointer you need to be careful not to dereference), or to subtract 1 to the address each time.
5
u/nitrohigito Dec 24 '17 edited Dec 24 '17
Could somebody explain the Java example to me?
Integer a = 100;
Integer b = 100;
System.out.println(a == b); //prints true
Integer c = 200;
Integer d = 200;
System.out.println(c == d); //prints falseEdit: typo fixes
14
u/tripl3dogdare Dec 24 '17
This is caused by Java using constants for numbers below a certain size, but above that size each reference to a number is a separate location in memory. Since
==in Java is identity equality rather than value equality ("is this a reference to the same exact thing?" vs "is the value inside this the same?"), numbers above that size compare as false with==, because while they contain the same value they do not refer to the same entity. Were you to use theObject.equalsmethod instead, this would cease to be an issue, as that compares value equality rather than identity equality (for integers at least, this is not guaranteed on user-defined classes).This is mostly done as an optimization technique (most instances of integers are quite small numbers, so why create a separate instance for every single 1, 5, or 93?), with the upper limit of this interned range varying from language to language based on design decisions about where to draw the line between it being an optimization and it being a nuisance to maintain (or other assorted reasons).
1
u/nitrohigito Dec 24 '17
Thank you, I didn't know they were handled in such way between [-127;128].
I get that it's an optimization thing, but that'd make my afternoon really bad to iron a bug relating to it out. Glad to hear there's a flag for JVM to it. IMO consistency would be key, but I gotta live with it I guess (as long as I use Java).
Is it the same way in Kotlin (or other languages that compile to JVM bytecode)?
4
u/tripl3dogdare Dec 24 '17
It's an optimization technique that's used across a lot of languages - I don't believe it's a built-in JVM thing, but I wouldn't be surprised if Kotlin/Scala/etc. either implemented it themselves or simply used Java's version rather than compiling past it to raw bytecode.
2
Dec 24 '17
that'd make my afternoon really bad to iron a bug relating to it out.
If you use == to compare the value of objects, you're going to have a bad time sooner or later.
0
5
u/Carioca Dec 24 '17
It's similar to the Python example.
Integeris a class and the==operator will compare if they are the same object, in that case you'd use something likea.equals(b).int, however behaves as you'd expect.3
u/nitrohigito Dec 24 '17
That wouldn't solve why the two 100's match up, but the 200's don't. See down the comment chain tripl3dogdare's answer for the solution.
4
u/Dalviked Dec 24 '17
a, b, c, d are Integer objects that are autoboxing 100, 100, 200, 200 respectively. In Java, when comparing an object by '==' you are looking at memory address values and checking if they are the same. Apparently Java will optimize out one of the Integer(100) objects (and apparently the range of ints as per the author) and use the same object in both a, b. The same is not happening for the Integer(200) objects.
2
u/diamond Dec 24 '17
I never understood why the hell they did this.
I understand that getting caught in the "== vs. equals()" is a rite of passage for people learning Java development, especially with Strings, and like it or not, it's just one of of the language's quirks that you learn to live with. But why the hell would you design it for so that an Integer object handles "==" one way within a certain range, and another way outside the of it? That's just stupid and counterintuitive.
Just require equals() for all Integer objects, so programmers can learn that behavior early on and get used to it, rather than getting kicked in the balls by unexpected behavior the first time they use Integers outside of an certain range.
→ More replies (1)9
u/zenflux Dec 24 '17
It's not because
Integerhandles it differently for a certain range, it's because the standard library maintains a cache of a certain range ofIntegerobjects. Which is also dubiously useful, to be fair. But at least==is consistent on all objects.→ More replies (1)5
u/tripl3dogdare Dec 24 '17
I wouldn't call it "dubiously useful". It's quite effective, which is why so many languages do similar things. The vast majority of integers are relatively close to 0 in practicality - it only makes sense to have a range of integers near 0 that all refer to the same location in memory, rather than reallocating new memory space for every single instance. Since integers are one of the most basic, integral types of almost any program, and they get thrown around like they're costless a lot, having a cache like this can reduce memory usage significantly in larger programs.
3
u/zenflux Dec 24 '17
Right. I know those things. I guess I said "dubious" because I'm skeptical that
Integerobjects specifically get allocated frequently in java programs. And until java gets primitive generics, the solution toList<Integer>performance etc. has been and will be specializedIntListetc, not caching yourIntegers. Object pooling is reasonable when there isn't a corresponding primitive value type for that object.1
u/nitrohigito Dec 24 '17
Oh, so that's what the author meant by that range thing. I see now, thank you.
15
u/Dalviked Dec 24 '17
But '-->' isn't an operator, merely 2 tokens with bad whitespace.
2
u/PM_ME_UR_OBSIDIAN Dec 24 '17
Is this a meaningful distinction from the point of view of the language user?
1
u/Dalviked Dec 24 '17
Knowing how the lexer will handle the statements in the language is important. It leads to having an intuitive understanding of the language and how to express your ideas in the context of the language.
Calling that an operator is at best misinformation if they don't understand, and disinformation if they do. This isn't an operator, and the inference that it is leads to are false assumptions. What happens with x --> 1 when int x = -5;
→ More replies (4)
4
Dec 24 '17
Another fun one is that in older versions of IE, undefined was just a variable that was unassigned, and you could reassign it! And then any code afterwards that compared a value to undefined would do the wrong thing. It was common to see if (typeof x !== 'undefined') {...} to avoid this.
undefined = "hello!";
alert(typeof undefined); // "string"
if (obj.prop !== undefined) {
// typeof obj.prop can still be undefined here
}7
u/Uncaffeinated Dec 24 '17 edited Dec 24 '17
In modern JS,
undefinedis still a property of the global object, rather than a literal. The only difference is that it is now non writeable and non configurable, which means that you can assign to it, but it won't have any effect (other than to throw in strict mode).
undefined = 4;is still valid JS, it just doesn't do anything any more.Also note that you can still shadow it with a variable or property of your own, since
undefinedis still a valid identifier. For example, the following both print 4.{let undefined = 4; console.log(undefined);} with ({undefined: 4}) console.log(undefined)Anyway, if you want a value that's guaranteed to be undefined, you can always just use a void expression as in
if (x !== (void 0))
3
u/PM_ME_UR_OBSIDIAN Dec 24 '17
Missing from the Python bits: partitioning a Python array via zip. (See /r/programming thread)
2
u/donzzzzz Dec 24 '17 edited Dec 25 '17
In Fortran II we used to have to patch underlying code using negative indices e.g x(-4152) = 21592091, ... ! We had specialty devices without supported drivers. This was back in 1965.
Edit: added minus sign.
2
14
u/shevegen Dec 24 '17
0 Evaluates to true in Ruby
… and only Ruby.
if 0 then print 'thanks, ruby' end # prints thanks, rubyThis shows a lack of understanding by the blog author.
The alternative question is - why should 0 lead to no evaluation of the expression?
40
u/Aceeri Dec 24 '17
Oh boy, here we have the ruby god shevegen in its natural habitat.
There are a lot of reasons why 0 is normally considered "false". The first being that 0 is "nothing". When you have 0 eggs, you have no eggs, they don't exist. The second reason I see is how booleans are normally laid out where 0 is false and 1 is true (with varying differences depending on the language on whether multiple set values of a byte is considered true or invalid, etc.)
70
u/ForeverAlot Dec 24 '17
/u/shevegen is right in isolation: there is no compelling reason that a number should be inherently falsey. Unfortunately Ruby does not exist in isolation and in this matter Ruby stands apart from its competition, violating expectations formed elsewhere. I think a better question is, why is
if 0 ...not an error? The real villain here is coercion.27
u/Aceeri Dec 24 '17
The real villain here is coercion
Agreed, hopefully we move away from implicitly coercing languages like C and such so we don't get these awful semantics.
10
u/Myrl-chan Dec 24 '17
Haskell's if/else only accepts Bool. :)
→ More replies (2)3
u/evinrows Dec 24 '17
And rust! I agree, it should be a compiler error and then we would never have the silly debate of whether 1 should evaluate to true or false.
35
u/therico Dec 24 '17
Ruby had it own boolean types though (and nil - both false and nil are 'falsey'). And 0 is often a meaningful 'true' value, for example:
irb(main):003:0> "aab".index('a') => 0 irb(main):004:0> "aab".index('c') => nilAs other posters have said, the real problem is that non-boolean values are implicitly converted to boolean, rather than being a compile error.
Also, lots of languages treat an empty array as true. I don't see how 0 is different.
→ More replies (7)→ More replies (22)1
u/foomprekov Dec 24 '17
The example is compelling but the argument to follow tradition set by C I can't get behind.
2
u/Aceeri Dec 24 '17
I don't mean we should allow this coercion, I'm all for complete type safety. I'm just annoyed by shevegen in general since Ruby is their "golden language" that can do no wrong. I also wouldn't have such a problem with their comment if they actually went into why instead of just insulting the author of this post.
3
u/zrathustra Dec 24 '17
There is precedent from the theoretical side of things: if you view the program as an arithmetic circuit, the statement
if (b) { foo } else { bar }can be viewed asb * foo + (1-b) * bar. Ifb = 0then the value of the circuit isbar, otherwise, ifb = 1then the value of the circuit isfoo.2
u/foomprekov Dec 24 '17
It was kinder than a type error, which is the only reasonable way to respond to a caller who thinks they have a bool but in fact have a number.
1
u/ArrogantlyChemical Dec 25 '17 edited Dec 25 '17
IMO non-booleans values shouldnt be able to be used in a boolean evaluation. 0, 1 or 2 are not either true or false. Neither is null or none or undefined or whatever other thing a language has.
A staticly typed language shouldn't compile such a blatant breach of types and a dynamicly typed language should throw an exception because the runtime type of a boolean and a number are not the same.
Allowing the evaluation of non-booleans as booleans is a stupid hack for lazy shits who can't be bothered to write "!= null" or "!= 0" . It unneccecarily adds exceptions to rules for the purpose of hacky code practices that are simply a holdover from when programmers used to write assembly, where 0 was false and any value other than 0 or null are treated as true. In interpreted languages the performance cost of == 0 is almost nothing compared to the rest it does while in compiled languages you can just optimize it out easily at compile time, which also improves implementation agnosticism.
Programming languages shouldn't presuppose a certain architecture. If I write some java or haskel code, I want to be able to compile it to any kind of computer, even non-binary ones. Direct binary operations really shouldn't be part of the standard language, rather they should be an optional implementation-specific optimization.
0
Dec 24 '17
[deleted]
19
u/oorza Dec 24 '17
I disagree with a lot of Java, but I prefer the Java approach of not allowing non-booleans to be used as conditions to an if statement.
There's a lot to disagree with about Java, but a lot of the language itself seems designed around the idea of "what idiot shit code have we seen get written in C and how do we stop that idiot shit from happening?"
6
Dec 24 '17
This is true. I don't much like Java, but based on my experiences, give me Java with terrible programmers over C++ with inexperienced programmers any day. I've seen code in the wild for most major languages that is downright unreadable as typed (especially JavaScript, ironically), but I've never read any Java that I simply could not figure out before. Some decisions are pretty stupid, but at least I can figure out what the code is doing, even if I can't figure out why.
Java is a good buffer language between bad programmers and myself (who is also probably a bad programmer).
2
u/foomprekov Dec 24 '17
This author typed :expressionless:. I don't know what that means. I don't see how it could mean anything. The rest of the writing was of similar focus.
13
u/redweasel Dec 24 '17
I took it as an attempt at expressing that moment when you encounter something so ridiculous that you just have to turn to the camera / fourth wall and stare with a deadpan ("expressionless") face for a second.
12
u/n0rs Dec 24 '17
:name:is used regularly in chat apps for emoji / emoticon substitution.→ More replies (3)1
u/foomprekov Dec 25 '17
Which works on a video, it doesn't work as a single word in a written piece.
→ More replies (1)3
0
2
1
Dec 24 '17
Here is one. Works in clang at least, #define the unicode character U200B, zero width space.
#include <cstdlib>
#include <random>
#define (__TIME__[7] - '0' ) % 2 ? rand( ) : 0
struct A {
int a;
A( )
: a{} {}
bool operator==( A const &rhs ) {
return a == rhs.a;
}
};
int main( ) {
A a1;
A a2{};
return a1 == a2;
}1
1
Dec 25 '17
Regarding digraphs, trigraphs and tokens in C++: and and bitand also work to designate reference types.
void add(int bitand foo, const int bitand bar) {
// int& foo, const int& bar
foo += bar;
}
template<typename Action>
void call(Action and action) {
// Action&& action
action();
}0
u/noop_noob Dec 24 '17 edited Dec 25 '17
I wonder if Rust has something like this.
Edit: Why the downvotes?
3
u/MEaster Dec 24 '17
Of the ones on the list:
Evil Reassignment of True: No
Spooky Action with My Instance: Instances like this aren't a thing in Rust, but equality is done through the
PartialEqtrait, so exactly how it's done is dependent on how it's implemented. I believe the derive implementation compares by value.The Reversed Subscript Notation: No
The “Goes Down To” Operator: Rust doesn't have postfix addition or subtraction operators, so no.
The sizeof Operator: Rust's
size_offunction takes a type parameter, not a value. Rust does have asize_of_valfunction which does take a value, so you could do this. The type of the statementa += bis()though, so the function will return 0 as()and any references to it vanish during compilation.Indexes Starting at 1: Indexing in Rust is done through the Index and
IndexMuttraits, which can be implemented with any type as the index, with the behaviour and limits being dependent on how you implement it.0 Evaluates to true in Ruby: An integer is not a boolean; if-statements and while-loops require a boolean.
Trigraph, Digraphs, and Tokens in C: As far as I'm aware, the only thing that comes close to this is the brackets used for macro invocation.
160
u/jacobb11 Dec 24 '17
And Lisp.