HNHacker News
TopNewBestAskShowJobs

nikic

1,920 karma · joined December 16, 2011

Blog: http://nikic.github.com/ Email: nikic@php.net
submissionscomments
nikic··on Ruby `reject!`
If the function was implemented as an infinite loop, would you consider the code working correctly as well? After all, the result after execution of the function is always correct (ex falso quodlibet).
nikic··on Ruby 2.4.0 Released
It looks like recently, there has been a convergence of hashtable implementations across a number of programming languages. Details differ, but the general structure is now to use two arrays, one for storing the data in insertion order (thus maintaining order without a doubly linked list), and another array serving as a hash, which contains indexes into the data array. This general idea works both with chaining and open addressing. In the last couple of years PHP (first HHVM then Zend), then Python (first PyPy then CPython), then Ruby (MRI) have switched to using this layout. Interestingly, Python has previously not made guarantees about order of hashtable elements, so this layout is advantageous even if maintaining insertion order is not a hard design constraint.
nikic··on PHP 7.1.0 Released
Copy-pasting from an answer on reddit (https://www.reddit.com/r/PHP/comments/5eu9pc/whats_new_in_ph...):

Because the alternative conflicts in case we ever introduce generics. Consider <?php new Foo<Bar?> ?>. This could either be a generic instantiation, or it could be the same as <?php ((new Foo) < Bar) ?> ?> (which is how it is currently interpreted -- this is valid PHP code!)

Of course, you could specify how this is to be interpreted and implement the necessary parser hacks to make it happen, but it's best to avoid the issue altogether by using ? as a prefix.

I assume that this is also the reason why Hack does the same.

nikic··on Ruby 3x3: Matz, Koichi, and Tenderlove on the Future of Ruby Performance
We tried to implement an LLVM based JIT compiler for PHP. There's basically two problems: First, LLVM is excruciatingly slow. If I remember correctly, it took more than a minute to compile all the WP functions for a front-page access (this is something like 100k VM instructions translated to LLVM bitcode). Second, LLVM is not great at optimizing the kind of IR that a JIT compiler for a dynamic language emits. It is much more important to perform language-specific optimizations prior to lowering. HHVM basically came to the same conclusion [1]. They lowered vasm to LLVM IR and let LLVM perform additional optimizations and native codegen. The difference was basically noise.

On the other hand, there are projects that do successfully use LLVM for JIT. We now experiment with dynasm, which doesn't optimize, but is fast and much more pleasant to use. libjit looks like another popular option. [1]: http://hhvm.com/blog/10205/llvm-code-generation-in-hhvm

nikic··on PHP 7 at Tumblr
Our perf work in the 7.1 cycle hasn't shown any significant gains on real applications (we have some improvements for computationally intensive code -- like arithmetic inside tight loops).

Whether or not the JIT will bring a major improvement for applications is not yet clear, but the hope is obviously there.

nikic··on WoSign Incidents Report Update [pdf]
> The charged 42 backdated certificates are an intentional activity that we try to help the desperate customers since there are more than 3M users still using Windows XP sp2 in China. We like to make things simple that don’t realize how serious this solution was.

I think this is all there really is to it. Some customers wanted to have backdated SHA1 certificates so they could continue supporting platforms that do not accept SHA256 certificates. WoSign decided to oblige them.

nikic··on OpenSSL Security Advisory - 26 Sep 2016
Thankfully the RCE vulnerability is only in OpenSSL 1.1, which is probably not commonly used yet.

Does the second issue imply that OpenSSL does not have any automated tests for the CRL functionality?

nikic··on Google’s lawyers are asking to find Oracle’s lawyers in contempt of court
This article reads very weirdly to me. Are they arguing that disclosing confidential information, and subsequently opposing steps to contain the disclosed information, is perfectly fine because ... it can be found on the internet, precisely because of this disclosure? This makes absolutely no sense to me.
nikic··on Robin Hood Hashing should be the default hash table implementation (2013)
One consideration to take into account when choosing your hash table implementation is how much it is susceptible to the quality of the used hash function. Hash tables using chaining are pretty robust against low-quality hash functions. Using the same with a Robin Hood table will land you in a catastrophic case very quickly.

This is the issue I ran into when investigating use of RH hashing in PHP -- the average case had good performance, but there were pathological cases exhibiting extremely high clustering in a mostly empty table. The reason was the low-quality hash (for integer keys the identity function).

nikic··on Inter-Procedural Optimization and Derefinement
Division by zero is undefined behavior, so the compiler is free to assume that the b==false branch is unreachable.
nikic··on LHCb unveils new particles
This result is interesting not because tetraquark states were not previously expected to exist, but because it allows us to verify whether theoretical predictions about them coincide with the experimental results. I don't think there was an expectation of hadrons being limited to two and three quarks only.
nikic··on Introducing a new, advanced Visual C++ code optimizer
To handle this case some SSA implementations add a concept of "pi" nodes, which are used to artificially split variables on branches that establish some useful data flow property.

    x1 = ...
    if (x1 > 0) {
        x2 = pi(x1 & RANGE[1..])
        use(x2)
    } else {
        x3 = pi(x1 & RANGE[..0])
        use(x3)
    }
    x4 = phi(x2, x3) // if used
I have placed the pi nodes in the blocks, but semantically they are placed along the control edge.

Ref e.g. e-SSA in the ABCD value range inference algorithm.

nikic··on Clang emits memcpy for std::swap, which can introduce undefined behavior
The bug report contains a quote from the C++ standard: "An rvalue or lvalue t is swappable if and only if t is swappable with any rvalue or lvalue, respectively, of type T"

What does this statement mean and why is it not tautological?

nikic··on Efficient Integer Overflow Checking in LLVM
Isn't value range inference for eliminating overflow / out-of-bounds checks, and LCM (/PRE) for hoisting checks out of loops pretty standard in any optimizing compiler nowadays?
nikic··on NPM and Left-Pad: Have We Forgotten How to Program?
A fun r/programming subthread about this package: https://www.reddit.com/r/programming/comments/4bjss2/an_11_l...

Those are just the three top-level dependencies. The package has 9 recursive dependencies.

There's also a nice table explaining how a package called "is-positive" managed to reach version 3.1.0.

nikic··on Peachpie – PHP Compiler to .NET, Part 2
The language changes that happened in PHP 7 are, with maybe two exceptions (func_get_args and foreach details) not related to performance. So if you're comparing performance (and not language support), there is nothing wrong with comparing a Peachpie PHP5 implementation to a Zend PHP7 implementation. The Zend implementation does not derive any significant benefit from being PHP7 compliant (as far as performance is concerned).
nikic··on What every compiler writer should know about programmers [pdf]
What I think many people fail to realize is that a large part of the code as a C compiler sees it is machine-generated. While I certainly do not tend to literally write out `if (1 != 0)` conditionals in my code, these and other similarly trivial expressions, will be introduced en-masse after macro expansion and aggressive inlining.

And in this context, macro-expanded, inlined code, exploiting the assumption of no undefined behavior occurring starts making a lot more sense. Sure, if you consider something like

    int x = *ptr;
    if (ptr != NULL) {
        *ptr = 1;
    }
you may not unreasonably say that, as there is an explicit ptr != NULL check in there, probably that's what the programmer intended -- so we should not replace ptr != NULL with a constant 0 because that pointer was already dereferenced.

However if the real code is

    int x = *ptr;
    do_something_with_ptr(ptr)
and the do_something_with_ptr() function just happens to contain a NULL-check at some point (because it is written for a more generic purpose and not use in just this place), then not dropping that NULL-check becomes a very significant missed optimization opportunity.

If the compiler wouldn't optimize that out of consideration for the possibility of the former hand-written code, that would incur costs on the programmer. He might have to split do_something_with_ptr() into two functions, one doing NULL checks and one not doing it. He may have to add explicit compiler assumption / unreachability annotations.

The whole argument goes both ways, performing optimizations that break broken code has a cost (people have to fix it) and not performing those optimizations for working code (people have to manually optimize it).

nikic··on Phan by Etsy – A Static Analyzer for PHP 7+
Static analyzers for different languages detect different types of errors. A static analyzer for PHP may try to find type mismatches. For statically typed languages that's obviously not relevant, as the compiler already handles it. On the other hand, a static analyzer for C may try to find use-after-free bugs. For PHP that in return is not relevant, as the compiler/runtime handles it already.

While some compilers do ship with static analysis components (e.g. Clang), static analyzers are usually distinct from compilers. Doesn't matter it for static or dynamic languages.

nikic··on Phan by Etsy – A Static Analyzer for PHP 7+
I think this is the first time I've seen PHP accused of getting "so much love"...
nikic··on Phan by Etsy – A Static Analyzer for PHP 7+
You make it sound like people don't implement static analyzers from scratch for every static language out there. Static analysis is not obsoleted by using a "static" language. You can't even say that static analysis is easier in a static language (the problems you deal with are just different).

Every language with a non-trivial number of users tends to have a couple (or maybe couple dozen) different static analyzers of varying quality. This is one of the PHP static analyzers.

nikic··on GC and Rust Part 1: Specifying the Problem
Having a GC can make the implementation of lock-free data structures significantly easier. Without GC you effectively end up implementing a sort of very specialized garbage collection scheme for the data structure.

This is a very nice article about using epoch-based memory reclamation for lock-free datastructures in Rust: https://aturon.github.io/blog/2015/08/27/epoch/

nikic··on An interesting data structure with search time O(sqrt n)
That's true, I got confused with min and max there. gre's suggestion of using a min-max heap (if deletion is required) seems a reasonable workaround for this issue.
nikic··on An interesting data structure with search time O(sqrt n)
Per the last posts: Number of heaps: O(n^(1/3)). Maximum elements per heap O(n^(2/3)).

Lookup of an element. Find the heap with the element (i.e. element between maximum of previous heap and this heap). Perform linear search in heap. Worst cast complexity O(n^(1/3) + n^(2/3)) = O(n^(2/3)).

Insertion of an element. Find the last heap those maximum element is still larger than the element. Extract top element of the heap and insert the new element instead. Then propagate upwards (i.e. extract top of next heap and insert top of previous heap, etc). Worst case is O(n^(1/3) + log(n^(2/3)) * n^(1/3)) = O(log(n) * n^(1/3)).

Deletion of an element. Find the heap with the element (i.e. element between maximum of previous heap and this heap). Remove the element from it. Extract top of next heap and insert it into this one. Then continue propagating upwards. So this is O(n^(1/3) + n^(2/3) + log(n^(2/3)) * n^(1/3)) = O(n^(2/3)).

Building the structure. Why is this O(n)? If you have already segregated the array into segments for the separate heaps, heapifying them would be O(n). How can the segmentation be done in O(n)?

Edit: Using the suggestion of splitting up according to 1+3+5+..+(2n-1) = n^2 we'd get:

Search: O(sqrt(n) + sqrt(n)) = O(sqrt(n))

Insert: O(sqrt(n) + log(sqrt(n)) * sqrt(n)) = O(log(n) * sqrt(n)

Delete: O(sqrt(n) + sqrt(n) + log(sqrt(n)) * sqrt(n)) = O(log(n) * sqrt(n))

nikic··on StackOverflow modding itself out of existence
I wouldn't consider that particular question to be noise, even though it does not really fit the SO format. By "noise" I'm mainly referring to exceedingly simple questions, which could have been solved by even minimal research or debugging. Questions that have already been asked many, many times and only vary in your precise code.

My point here is that, in my experience, the main problem of StackOverflow is too little or ineffective moderation, rather than the other way around.

nikic··on StackOverflow modding itself out of existence
Questions with many upvotes do require more deletion votes. E.g. this question needed 10 votes, rather than the usual 3.
nikic··on StackOverflow modding itself out of existence
After seeing a couple of posts like this, I'd like to provide an alternative perspective:

I no longer actively answer questions on StackOverflow, because it is too hard to find worthwhile questions between all the noise. If someone specifically asks me to answer something, I will do it, but trying to find interesting questions on StackOverflow has become impossible due to the high influx of very low quality material.

There was a period where I'd try to help moderation by closing an deleting questions, but at some point you just realize it's a loosing battle and give up.

nikic··on When ‘int’ is the new ‘short’
I think the most interesting bit here is this:

> Now, the more astute reader will point out that I just sent over 4 gigabytes of data over the internet; and that this can’t really be all that interesting - but that argument is readily countered with gzip encoding, reducing the required data to a 4 megabyte payload.

This was pretty much my first thought on seeing the IOBuffer signature - "That exploit payload is going to be huge". But things are not always as they seem and using gzip to generate a large string on the client is something I had not previously considered.

nikic··on PHP 7's new hashtable implementation
The maximum load factor is 1. A lower load factor only makes sense if open addressing is used.
nikic··on PHP 7's new hashtable implementation
Yes, pData and pDataPtr are no more. They have always been pretty pointless - both could have been dropped even retaining the rest of the previous implementation by using a struct hack layout. In the new implementation they aren't needed because it's specialized to zvals (our 99%-or-so use case).
nikic··on The Fourier Transform, explained in one sentence
I have no idea about engineering, but I don't see how a physicist would not know this. Basis transformations in infinitely dimensional Hilbert spaces are an integral part of quantum mechanics. The Fourier-transform in particular is used for transformation between space |r> and momentum |p> representations, but it's also common to use energy representations |E_n> where the orthonormal basis is typically somewhat more exotic (e.g. given by a Gaussian multiplied with Hermite polynomials, as is the case for the QHO).
← PreviousPage 3 of 6Next →