[HN Gopher] Perl code that is syntactically correct only on Fridays ___________________________________________________________________ Perl code that is syntactically correct only on Fridays Author : pabs3 Score : 410 points Date : 2022-02-16 12:46 UTC (10 hours ago) (HTM) web link (github.com) (TXT) w3m dump (github.com) | saba2008 wrote: | Somewhat related: | | Perl Cannot Be Parsed: A Formal Proof (2008) | https://news.ycombinator.com/item?id=5770531 | rabbits77 wrote: | Well, to be a little pedantic, Perl cannot be statically | parsed, since some constructs require runtime context. | | If it could not be parsed it could never work! | | And this is totally OK in my book, I use Perl for prototyping | ideas and an expressive language that allows creativity from me | the programmer is a feature as it promotes looking at a problem | from multiple aspects. | avgcorrection wrote: | "Cannot be X" most often means "in the general case". (In the | context of computability.) | lmm wrote: | > Well, to be a little pedantic, Perl cannot be statically | parsed, since some constructs require runtime context. | | If you're going to be pedantic, it's important to be correct; | there's no such thing as dynamic parsing. | | > If it could not be parsed it could never work! | | What's the logic here? An interpreter doesn't have to operate | on an AST, a language doesn't have to have a nontrivial | grammar (consider Brainfuck). Perl is just a language in the | same category: it doesn't have a (true) nontrivial AST, it | doesn't have a (true) nontrivial grammar, and it can't be | (truly, nontrivially) parsed. | samatman wrote: | > _there 's no such thing as dynamic parsing_ | | As long as we're indulging in pedantry, this is incorrect | presuming dynamic means what it usually means. Any regular | expression constructed at runtime contradicts you. | | Modifying your core parser at runtime though, who would do | such a thing? Other than reader macros in Common Lisp I | mean. Are we going to argue this means Common Lisp doesn't | parse if we add reader macros at runtime? A peculiar | argument. | | Now. Should we talk about whether doing that is a good | idea? A lovely and separate conversation. I agree with GP | that since Perl will spit out a parse tree, it does in fact | parse, and since it's not static, well, it's dynamic. | | Which we can prove by, I dunno, writing some Perl which | only parses on Fridays. Right? | bmn__ wrote: | > Modifying your core parser at runtime though, who would | do such a thing? | | Perl? Its numerous language extensions allowed it to stay | competitive for such a long time. Every time someone says | "language X can do Y but Perl doesn't have that syntax", | a new CPAN module is born to amend the shortcoming. | lmm wrote: | > Are we going to argue this means Common Lisp doesn't | parse if we add reader macros at runtime? A peculiar | argument. | | Peculiar how? Isn't that just common sense? | gvb wrote: | <pedantic> | | The code is never syntactically correct however the syntax error | is not identified by the Perl interpreter on Fridays. | | </pedantic> | jordanmorgan10 wrote: | Gah why did I take up programming for a living :| | Leherenn wrote: | I have seen some code that would fail based not on time but | location. | | Once we had a client from the Netherlands that complained about a | bug that we could not reproduce. We tried to reproduce it by | simulating his position, but to no avail. Turns out he was in a | very specific, slightly depressed, area that was a few | centimetres below mean sea level and that the code didn't like | negative altitudes. | | Another one only happened in the southern hemisphere. Given we | were based in Europe and it was winter, we asked whether we could | do some more tests in Australia to make sure there were no more | bugs, but sadly it was denied. | reneberlin wrote: | I don't get it! It is clearly written in the code, that the | progam should behave this way. | | Is the proof, that perl is capable of this behaviour?! I don't | get it - what is the point? | | I read all the comments and still don't get it. What am i | missing? | iLoveOncall wrote: | What makes it "special" here is the fact that it will COMPILE | only on a friday. | | It's not a runtime error but a compile time error. Because yes | otherwise I would agree that it's doable easily in every single | language. | high_pathetic wrote: | Isn't perl an interpreted language? Or I am missing a point? | | What will happen when the command is `perl -c friday.pm`? | ghayes wrote: | But isn't this possible with any language that has a pre- | compilation step? Perl is certainly conflating its passes (as | explained by other comments above), but in rust you could add | a check in build.rs or use macros in C to accomplish the | same, right? | bachmeier wrote: | Here's a D program that only fails to compile if the last | digit of the current number of seconds is 4: | | enum timestamp = __TIMESTAMP__; | | void main() { pragma(msg, timestamp[$-6..$-5]); auto a = 4; | static if(timestamp[$-6..$-5] == "4") { auto a = 7; } } | JohnHaugeland wrote: | they made a branch where one side is defective and the other | isn't | | they only follow the non-defective side one day a week | | because perl doesn't forward analyze, it never sees the error | on other days, and doesn't fail | | the presentation is false. this code is always wrong. it's just | that the bug is only visible under certain conditions. | bachmeier wrote: | Was going to say the same thing. I thought it would be | something wrong with the language. If you're going to write | code that's different depending on the day of the week...meh. | wutbrodo wrote: | You can write code in any language that fails at runtime | depending on the day. What's notable about this is that its | _syntactical correctness_ depends on the day, which is not | possible to achieve in many languages. | | What's being noted is the degree of flexibility that Perl has | with respect to its execution environment. | | Though if you include preprocessors, you expand the number of | languages for which you can do something similar. | JohnHaugeland wrote: | This code is always syntactically incorrect. | | It is merely that the problem branch is only occasionally | followed. | praptak wrote: | In similar vein: parsing C++ is literally undecidable: | https://blog.reverberate.org/2013/08/parsing-c-is-literally-... | | You can't even decide if a particular "*" is multiplication or a | pointer dereference until you resolve templates, which is Turing- | complete. | vidarh wrote: | Unless something has changed a lot, C++ templates at least only | used to be Turing complete if you assume you're allowed | unlimited recursive template applications, and compilers were | free to restrict that (and did). Has that changed? | | In theory I agree with you that this is horribly ugly - I very | much prefer simple grammars (the irony being my favourite | language to _use_ is Ruby, which has an atrocious grammar). In | practice these parses are rarely that hard to resolve. | praptak wrote: | It's not the undecidability itself that is the problem | though. The undecidability is just an indicator how horribly | complicated C++ is to compile. | | You cannot even construct the full parse tree before | evaluating a mini-language that is Turing complete. Related | article: why C++ compilation is slow | (https://digitalmars.com/articles/b54.html) | vidarh wrote: | I have a half-finished Ruby compiler sitting around, so I'm | a bit jaded when it comes to how complicated something is | to compile. C++ is complex, but at least it's reasonable | well specified. | steerablesafe wrote: | Well, C++ now has constexpr functions that can run in compile | time, and do basically arbitrary computation. But it also has | implementation limits. | ncmncm wrote: | Compilers decreasingly encounter parses that depend on template | instantiation, as users move to new constexpr alternatives to | template metaprogramming. | | So the right implementation choice, for the compiler, is to | bull ahead with the common case, and throw the result away and | try the other path if you get to an inconsistency. Such | inconsistencies practically never happened in production code | anyway, and where they did it most usually was, and now almost | always is, a result of a bad edit. | | So the practical expense is keeping and then GCing old state as | it expires, which reduces to stack-like memory management, a | solved problem. | | We have not needed to go to JITting compile-time constructs, | (though it could still happen to expedite constexpr | evaluation). Rust might need to, soon, to accommodate parsing | under influence of macros, a chore growing with time, not | shrinking. (I.e., produce a new parser for each macro added, | and jump into it to finish the parse.) | johnnyo wrote: | I had an intern once who wrote similar code. They confused 12 | hour and 24 hour clocks, so the code would break after lunch. | | Unfortunately, the intern only worked the mornings, so it took | several days of back and forth before the bug could be finally | put to rest. | [deleted] | markstos wrote: | We had situation where if you worked late, the test suite would | consistently fail. | | Since developers rarely worked late and would give up when | hitting the "random" test suite failure and go home, the bug | persisted for months before the true cause was understood. | | Our time zone was UTC-5, and the test suite contained a local- | vs-UTC bug which only triggered between 7pm and midnight. | monkpit wrote: | I feel like this is relatively common (unfortunately) | Nextgrid wrote: | It is. I'm in London which means that our time is +/- 1 | hour of UTC depending on daylight saving time. | | There's been a couple projects where if I pushed a commit | between 11pm and 1am some tests would break. I'm pretty | sure the issue is inconsistent use of UTC vs local time | which during that period will differ by one day. | ipsi wrote: | One of the perils of working in the UK is _assuming_ that | you've been using UTC timestamps this whole time, and | then summer rolls around and suddenly a bunch of tests | start failing, and all your production logs are an hour | out because you were wrong, and actually used local | timestamps everywhere. Oops. | knodi123 wrote: | Ha. I had an intern who wrote code that blew up if the | timestamp of our DB server was ever >= 1 second _after_ the | timestamp of our app server. | | It couldn't fail at his desk, because he ran both servers | locally while developing. And it wouldn't fail in production in | the morning, since we had a cron job that synced the clocks at | midnight. It took until after 5pm for the clocks to drift | enough, meaning I was on call and the intern was not. | | But the bug didn't crop up until his code had been in | production for a couple of weeks, so it was a real pain in the | neck to track down. | inquist wrote: | > an intern who wrote code .... his code had been in | production | | You get what you pay for, eh? | mypalmike wrote: | Depends. FAANG interns can make (annualized) income at or | near 6 figures. | mywittyname wrote: | I've done equally stupid things as a senior dev. The | biggest difference, I guess, is that I had to fix the stuff | I broke. | [deleted] | twopsix wrote: | darkwater wrote: | A cronjob to sync the time instead of a proper NTP client | doesn't sound that good either. I know that each place has | its own weird things because historical reasons but NTP is | quite ancient. | knodi123 wrote: | Our sysadmin was being paranoid about how many memory- | resident programs we ran. he figured time syncing wasn't | important enough to justify a daemon, so he just ran the | ntpdate command on a daily schedule. It wasn't _that_ bad | - after all, how far can clocks drift in a single day!? | ;-) | xorcist wrote: | If you are to be paranoid about time, better be paranoid | about stepping time. Time discontinuities can trigger | bugs in the best of software. | tristor wrote: | > he figured time syncing wasn't important enough to | justify a daemon | | Time synchronization is very arguable THE most important | thing on a server (for numerous security related | reasons). | | How many moons ago was this incident? It's perhaps | forgivable ignorance in the 90s... not so much today. | Dylan16807 wrote: | For security? Kerberos usually has a 5 minute tolerance. | Are you saying that's wrong? Because if your | hardware/firmware isn't literally broken you won't drift | anywhere near that in a day. | | NTP can't properly fix a clock like that either since | it's often capped at adjusting the speed by one part per | two thousand. At most, with a consistently wrong clock, | that can handle about 30 seconds per day. Any worse than | that and you won't see much advantage over ntpdate. | shadowoflight wrote: | Guess it's time to change the `0` in that cronjob to a | `*/12`. | krick wrote: | Admin like that sound a lot worse than the intern. Unless | maybe if it's an intern-admin... | amelius wrote: | To be honest, I wrote code that blew up after the time server | updated the time from the network, a few seconds after | booting. | bentcorner wrote: | Personally I really don't like code that deals with time - | it's too easy to place a "get time stamp" call anywhere in | code. If it's down in the bowels of some piece of | functionality trying to test it becomes a headache. | [deleted] | sandinmyjoints wrote: | This is one of those pieces of software engineering wisdom | that only comes from experience. Try explaining to a newish | dev why they shouldn't `const now = Date.now()` or whatever | anywhere they want, but rather do it in one place for the | lifecycle and pass it around, and they will look at you | funny and think it's a waste of time. Classic case of | simple vs easy. Time has the potential to complect | everything it touches. | fegu wrote: | In Haskell, getting the time is an IO operation. Because | of this one tends to use the exact pattern you recommend. | kodah wrote: | > Classic case of simple vs easy. | | Personally, I think my definition of "simple" changed | over time. Much of that was influenced by the depth of my | knowledge of particular paradigms, whether that be | software or knowledge of the subjects I was writing code | for. | albrewer wrote: | I learned this the hard way. Now I wrap interactions with | system time in a container class so that, if need be, I | can finely control time inside my app in unit tests and | debugging. | Spoom wrote: | Oh yes. Any time I see code that tries to do some kind of | scheduling, the first thing I ask is if they have | considered using a library someone else has written. Way | too many things can subtly go wrong, but new folks tend | to think it should be easy, because how hard can it be to | work with dates? | duxup wrote: | > because how hard can it be to work with dates? | | Man they are so hard that you could go on for hours about | it. | | https://www.codingblocks.net/podcast/why-date-ing-is- | hard/ | munk-a wrote: | There are seven time zones in Indiana in the tz | database[1] - this doesn't count the two most used ones | America/Chicago and America/New_York there's also a | Kentucky tz that slightly spills into the state. Whenever | anyone makes any comment about dates and times being easy | to compute I just mention that yes, _there are seven time | zones in Indiana_. Now the actual issues tend to arise | when software makes assumptions like "every second will | actually occur", "each second only happens once", "every | minute has 60 seconds", "every day has 86400 seconds" | amongst a plethora of other bad assumptions... but those | are a lot more complicated to explain. I like leaning on | Indiana. | | 1. | https://en.wikipedia.org/wiki/Time_in_Indiana#tz_database | VTimofeenko wrote: | A great collection of those "every minute has 60 seconds" | assumptions and why they are incorrect: | | https://yourcalendricalfallacyis.com/ | tentacleuno wrote: | > because how hard can it be to work with dates? | | Oh man, tell me about it. Timezones are the worst. No | wonder so many people just give up and use Moment.js. | dheera wrote: | Use UTC UNIX timestamps (i.e. Date.now()) for ALL time- | related processing and only convert to hours/minutes when | taking input/output from the user. | anchpop wrote: | Hmm, I think you should use TAI over UTC because UTC has | leap-second corrections, Which means that the current | time + X seconds might not actually be X seconds from now | aidos wrote: | Uh oh, we're going there again. If you're doing anything | in the future, that's not always the correct thing to do. | (Instants vs wall time etc) | mypalmike wrote: | That's a good starting point, and certainly good advice | for marking current time and past times. But keep in mind | that future event absolute UTC can change due to | politics, e.g. a change in daylight savings rules, which | is less rare than you might imagine (https://en.m.wikiped | ia.org/wiki/Daylight_saving_time_by_coun...). That | concert scheduled a year from now at 8pm in UTC+5 might | actually end up occurring at 8pm in UTC+6. | jwandborg wrote: | I've been bit by bugs when coming to moment.js from other | languages. It's the only datetime library I knew of, | before you'll tell me about all the others, that mutates | the datetime object when you do arithmetic. | blowski wrote: | The PHP interops group recently added a Clock interface | for this purpose. There were many comments along the | lines of "what's the point?" | bitemix wrote: | Love the Rich references. | lordnacho wrote: | It's also one of those things that actually is simple in | restricted cases, then when you try to generalise it | blows up badly, and it blows up like a time bomb rather | than a landmine. When a time bomb explodes you don't | quite know when it was triggered, but you have to deal | with it then and there, learning a heck of a lot about | time libs in general before you can proceed. What's a | leap second, which years have a leap day, are time zones | connected to places somehow, and so on. Just so you can | fix your calendar that's part of a larger app. | jimmaswell wrote: | Not too bad testing these things with mocking libraries. | actually_a_dog wrote: | It could have been much worse. At least you didn't have a leap | year or timezone bug. I've exterminated more than one of those | in my time as an engineer, and it's never really any fun. | divbzero wrote: | Like many here, I've faced similar challenges in debugging | time-dependent code. | | What is the best way to set or mock system time during testing? | anned20 wrote: | If you tried, you couldn't even come up with this. | RandalSchwartz wrote: | I could. :) | lanstin wrote: | I had a coworker working on a data-pipeline sort of thing once. | They for some reason wrote their own date parser (Akamai logs) | and used a regular expression to find the month. For whatever | reason, the RegExp didn't work for March (I think) and so at | midnight 1 March the year of first deploy, we started dropping | all the logs as un-parseable (causing the NOC to think the | traffic had gone to 0 or our system was buggy). We all got | paged and eventually figured out it. It had been running in | live for several months without problems at that time. | usrusr wrote: | Fortunately we rarely use 12h clocks where I live. But that | opens up other avenues: if you are not much of an early riser, | a build script failing to deal with single digit hours can | remain undetected for a _very_ long time. | ihateolives wrote: | I once had to implement date picker that returned the date to | be sent to backend to fetch the day's reservations. It seemed | to work fine the day I implemented it. Next day it broke. | Turned out the widget returned MM/DD/YYYY instead of | DD/MM/YYYY. And I implemented it on 10th of October. | adhoc_slime wrote: | I've learned the hard way that this is also dependent on the | user's date format set on their computer in some | libraries(iirc it was jquery ui date picker a few years | back). its liberating when you decide to throw it all out and | just use integers for all things not facing an end user. | mark-r wrote: | I'm a big fan of ISO 8601. Eliminates the confusion, and | sorts lexicographically too. | PixelOfDeath wrote: | Aliens landed on this planet, found out about the date format | MM/DD/YYYY, and left in a hurry. They are currently preparing | a gamma ray burst out of pure compassion and pity but also a | hint of disgust! | Ma8ee wrote: | Is that date format used anywhere outside the US? We have | always used YYYY-MM-DD. Which is very nice, if for nothing | you can use a single string sort if for whatever reason | need to sort them. | ant6n wrote: | In my world, there are two date formats: yyyy-mm-dd and | dd.mm.yyyy. | | Anything involving a slash is asking for trouble. | tzs wrote: | https://en.wikipedia.org/wiki/Date_format_by_country | wumpus wrote: | One perhaps apocryphal story that's kicking around out there | was that Draper Labs had a hard-real-time navigation system | which... took too much time computing something when the moon | was full. | nitwit005 wrote: | Saw some tests that had the same pattern. Passed half the day, | and failed the other half of the day. I assume it always worked | during India work hours. | alisonatwork wrote: | Fantastic. We had a similar problem with test code that always | worked on a remote team's computers during their work day but | failed when we got into the office and tried to run it in a | different timezone. | pc86 wrote: | Reminds me of an app I worked on a while ago where both the | server it was running on and the datetimes in the database | had to be in a specific time zone. Change either (including | changing both to an identical but different TZ) and the app | just failed to run. | vidarh wrote: | I've had to fix any number of test suite bugs as well as | regressions that happened because the people who wrote the | tests had ensured the test suite didn't (most of the time) | test what they thought it would by relying on date arithmetic | from current date and time... | salawat wrote: | Many people think that test suite authoring is easy mode. | It really isn't. Making a good test suite that actually | does a good job of tracking invariants is a royal pain. | ljm wrote: | As far as I'm concerned, writing tests is a different | skillset and its often underdeveloped. It then snowballs | into hating testing, because all you've experienced is a | poor test suite that gets worse over time. It's hard to | do well as you say, and it also gets glossed over in code | review as long as the tests pass. Do the tests actually | verify anything useful? Who knows, build is green! | | That's how you get an application with 50,000 unit and | integration tests that you can't run locally, and | requires massive parallelism in CI to finish in any | reasonable timeframe. | manojlds wrote: | That's standard runtime issue right? This is syntax error at | compile time. | dhosek wrote: | Kind of sort of. The catch here is that because runtime is | compile time with Perl, it's not exactly the same. Looking at | the code, it's kind of like having something like | #if (some C preprocessor expression that's true on Fridays | printf("Hello world!); #else printf; | #fi | | (although it's been long enough since I've written C that I | don't know if (a) there exists a C-preprocessor instruction | as per the above, (2) if the compiler will notice errors in | the unexecuted branch of an #if and (iii) if printf; would | give a syntax error). | | Another equivalent piece of code could be something along the | lines of the JS if (today_is_friday()) { | eval("2+2") } else { eval("--2abc") | } | garaetjjte wrote: | >(a) there exists a C-preprocessor instruction as per the | above | | There's no day-of-week but you could cause mayhem with | __DATE__ | | >(2) if the compiler will notice errors in the unexecuted | branch of an #if | | Compiler only gets to see preprocessor output, it won't. | | >if printf; would give a syntax error | | Perhaps surprisingly but no, it's just statement without | effect (containing expression returning function pointer to | printf). | nousermane wrote: | > you could cause mayhem with __DATE__ | | It takes some patience, but people do try: | https://stackoverflow.com/questions/11697820#16472369 | [deleted] | brian_herman wrote: | python: import datetime if | datetime.datetime.now().weekday() == 3: 1/0 | jwilk wrote: | Once you fix the indentation, this code is always syntatically | correct; it just happens to raise an exception on Thursdays. | cube00 wrote: | Another great reason not to deploy on Friday. | athenot wrote: | This leverages Perl's BEGIN block which runs before the main part | of the code. I suppose the same fun could be had in other | languages: if day_of_week is "Friday" | eval(piece_of_incorrect_code) else | do_sane_operation | saba2008 wrote: | Most other languages would require `eval` and having incorrect | code as syntactically correct string literal. | | But because Perl is parsed as it is executed, incorrect code | raises syntax error only when it is reached by execution. | btilly wrote: | _But because Perl is parsed as it is executed, incorrect code | raises syntax error only when it is reached by execution._ | | Sorry, but you're dead wrong. Perl is not parsed as it is | executed, which can be verified easily by writing a program | with a syntax error at the end, and seeing that it doesn't | run code at the top. Try it with the following program. | print "Hello, world\n"; This line raises a syntax | error before the previous line tries to execute. | | What is going on is that BEGIN blocks are special, they are | executed as soon as they are parsed. With them we can | interleave parsing and execution. | | In this case we're assigning to a symbol. And then the | parsing of the final line is dependent on whether or not that | symbol has a prototype. See | https://perldoc.perl.org/perlsub#Prototypes for what Perl | prototypes are, and to see why they would affect parsing. | petercooper wrote: | Ruby has that latter quality in many scenarios. For example: | p 'Friday!' if Time.now.wday==5 || h | JohnDeHope wrote: | Right, the beauty of this is that it's a _syntax_ error he 's | produced. Sure any language can write code to produce a | runtime error under any condition at all. And a lot of | languages have features that allow them to run code at | compile time, and similarly produce errors then too. But | those languages don't allow you to ruin the _syntax_ of the | language. I guess it 's something that requires macros. Would | it be safe to say that any language with macros can do this? | Or is there something even more interesting with perl going | on here? | im3w1l wrote: | Bash parses as it runs so something as simple as this works | if [ $(date +%u) -ne 5 ] then exit fi | ( | jwilk wrote: | You could check syntax of the whole file (even the | unreachable parts) with the -n option. | | But that's not bulletproof; consider this code (adapted | from <https://hal.archives- | ouvertes.fr/hal-01513750/document>): if [ | $(date +%u) -eq 5 ] then alias maybe='' | else alias maybe=: fi maybe for x | in; do :; done | | "sh -n" always reports syntax error, even thought the | script syntax is correct on Fridays. | lloeki wrote: | Bash even reads the file as it goes, so if you run a | "long-running" script (a sleep is enough), edit far | enough down, and write the file again, the previously | started bash will end up running the new content once it | gets up to reading where the change happened. | saba2008 wrote: | You can exploit it do distinguish whenever script is | `curl | bash`'ed. | | Add `sleep 1`, and detect pause on server. Then, if pause | detected - serve attack payload. If not - somebody is | careful enough to download and audit, so serve just the | script. | jwilk wrote: | https://www.idontplaydarts.com/2016/04/detecting-curl- | pipe-b... | | Discussed on HN: | | 2020: https://news.ycombinator.com/item?id=25356757 (133 | comments) | | 2018: https://news.ycombinator.com/item?id=17636032 (146 | comments) | | 2016: https://news.ycombinator.com/item?id=11532599 (122 | comments) | lloeki wrote: | It is formally proven that Perl can't be parsed! | | https://www.perlmonks.org/index.pl?node_id=663393 | bmn__ wrote: | It can be externally parsed with ambiguities. The article | is written by someone who authored such a parsing toolkit | about three years later. Despite what you may have | learnt, an ambiguous parse tree is still a useful thing | to have, we can build tools taking it into account, also | most existing tools can be modified in a straightforward | fashion to make use of the extra nodes. | | The real Perl parser disambiguates with heuristics and | run-time hints. | | There exists an unambiguous subset of Perl syntax that is | expressible with a BNF grammar, and such is amenable to | all parsers. http://p3rl.org/standard#DESCRIPTION | lloeki wrote: | Yeah, I always found the linked post to not be all that | serious about it anyway, just a funny, satisfying hacker | thing. | RandalSchwartz wrote: | It has been said that "the Perl compiler is based on | yacc, lex, smoke, and mirrors." | em-bee wrote: | i can do something like this with macros in pike: | | the following code produces a syntax error if the time is | less than 10 seconds after a full minute. | #define T __TIME__ #if T[6]-48 #define | X 1 #else #define X / #endif | void main() { write("%d, %c, %O\n", X, | T[6], T); } | skissane wrote: | Common Lisp is another language in which this should be | possible. Common Lisp allows you to run arbitrary code at | compile-time, and that code is allowed to modify the | language syntax (*READTABLE*, SET-MACRO-CHARACTER, etc). So | code could make itself syntactically invalid on Fridays by | changing the language syntax depending on the day of the | week. | | This goes beyond mere Lisp macros, in that ordinary Lisp | macro invocations still look like Lisp lists, while with | this you can make arbitrary changes to the syntax, you | could even make Common Lisp look like Pascal (if you really | wanted to) | | The designers of Scheme intentionally left this feature out | (which was also found in some of Common Lisp's ancestors, | such as Maclisp), but some Scheme | implementations/descendants included it anyway (as an | extension), such as Racket, Guile and Chicken Scheme. | tyingq wrote: | >incorrect code raises syntax error only when it is reached | by execution. | | That's not generally true for Perl. The BEGIN block is used | to get in that state here. _" Some incorrect code raises | syntax error only when it is reached"_ is true. | | It's generating this on Fridays: &f() / 1; | | And this on other days: f(/1;#/+); | | If you run the same code, but without BEGIN blocking the | assignment to *f, it isn't incorrect code. It evaluates as: | 'f' / 1; | ars wrote: | What happens if you run this code in a loop Thursday night | just before Friday? | | Does the parse that happens on Thursday take precedence or | is it reparsed every single time through the loop? | tyingq wrote: | The BEGIN block only runs once. That is: | while (1) { BEGIN {print "hello\n"} sleep | 1; } | | Will only print "hello" one time. | | You could loop inside the BEGIN block and then drop out | of the loop at some point. If you dropped out on friday, | after the code assigning *f, it would run correctly. So: | BEGIN { sleep 86400; *f = | (localtime->wdayname eq 'Fri') ? sub() {} | : sub {}; } f/1;#/+ | | Would run correctly if you started it on Thursday. | cestith wrote: | Perl is not parsed as it is executed. It is compiled to | opcodes then run. The BEGIN block, however, explicitly runs | code at compile time. It is literally compiling different | code on different days, then attempting to run it. | RandalSchwartz wrote: | Technically not opcodes, but internal Data Structures. A | serializer was written for that, to permit ".pmc files". | cestith wrote: | Oh, hey, Randal. Thanks for the correction. | | Looking forward to the next time we can have steaks and | Scotch. | yodon wrote: | Moral quandary of the morning: Do I point out the sign error or | do I just say please don't merge this? | runeks wrote: | That looks like a syntactically correct piece of code that | fails at runtime. | edgyquant wrote: | I miss Perl and it's community from the early-mid 2000s. Sure it | was bad for those who have to maintain but trying to create the | shorted and most unreadable possible was a fun pastime. | draw_down wrote: | me_again wrote: | I had a program once which failed every time it was 8 or 9 | minutes past the hour and worked the rest of the time. | | It parsed a string containing the time and sscanf treats "08" and | "09" as invalid octal numbers. Argh. | mrspuratic wrote: | Been there, a TCL web script, IIRC. This led to religious | processing of input with "regsub" (this predated TCL 8). Yuck. | | Also once fixed an inherited awk script that malfunctioned at | the end of year: a hardcoded month name array with November | missing. To this day I always populate any such lookup with a | loop and strftime() or appropriate. | pera wrote: | heh as soon as I saw the ternary expression I recalled the bug | report I submitted some years ago: | | https://rt-archive.perl.org/perl5/Ticket/Display.html?id=130... | didip wrote: | Wow. Do I need more reasons to hate perl? | | Yes, apparently. | kazinator wrote: | C code in similar spirit: $ gcc weird-0.c $ | ./a.out | | No output from weird-0 $ gcc weird-1.c $ | ./a.out foo(42) | | Output from weird-1. What is weird-0? $ cat | weird-0.c #include <stdio.h> void foo(int x) | { printf("foo(%d)\n", x); } int x = 42; | int main(void) { #if __LINE__ % 2 == 0 | typedef int foo; #endif foo(x); return 0; | } | | OK, how does weird-1 differ from weird-0? One blank line! | $ diff -u weird-0.c weird-1.c --- weird-0.c 2022-02-16 | 12:09:29.565563802 -0800 +++ weird-1.c 2022-02-16 | 12:09:38.185718722 -0800 @@ -7,6 +7,7 @@ int | x = 42; + int main(void) { #if | __LINE__ % 2 == 0 | | Explanation: { #if __LINE__ % 2 == 0 // | If this line number is even typedef int foo; // foo | is a typedef name for int #endif foo(x); | return 0; } | | If foo is a typedef name for int, then "foo(x)" is syntactically | _declaration_. It 's declaring a local variable x to be of type | foo, alias for int. | | If the typedef is missing, then foo(x) refers to the file-scope | identifiers: the function foo and variable x. It is a call to foo | passing the value 42 of x. | | The preprocessor conditional could easily introduce a syntax | error, but the issue in Perl is that a parsing decision (how the | / token is lexically categorized) is made based on the compile- | time value assigned to f. This is similar to the compile-time | meaning of foo we are setting up with the presence or absence of | the typedef. | kazinator wrote: | With a small change to the weird-0 and weird-1 programs: | $ gcc -O2 -Wall -W weird-0.c weird-0.c: In function | 'main': weird-0.c:15:7: warning: unused variable 'x' | [-Wunused-variable] foo(x); ^ | $ gcc -O2 -Wall -W weird-1.c weird-1.c: In function | 'main': weird-1.c:16:3: error: too few arguments to | function 'foo' foo(x); ^~~ | weird-1.c:3:6: note: declared here void foo(int x, int | y) ^~~ | | The change is in the foo function: void foo(int | x, int y) { printf("foo(%d, %d)\n", x, y); | } | | The call is now erroneous, and with the increased compiler | optimization level and diagnostics, the declaration case | diagnoses x being unuse | G3rn0ti wrote: | This is how it works: | | BEGIN { # an execution block that runs when the module is | compiled *f = # assigns to the symbol "f" | inside the symbol table ... | | (localtime->wdayname eq 'Fri') # is it Friday? | ? sub() {} # ... on friday an anonymous subroutine taking no | arguments : sub {}; # ... on every other day a | subrouting taking arguments | | } # closes the execution block | | # The following line executes the subroutine "f" and divides the | result by 1 on fridays | | # but on other days causes the interpreter to trigger a syntax | error because it expects | | # f to take an argument list "(...)" but receives an operator | "/". | | f/1;#/+ | Sophira wrote: | This is generally correct, but your final analysis is slightly | wrong and this is a perfect example of why Perl can be | difficult to parse. | | If you add a 1 to the end of the "f/1;#/+" line, so that it | becomes "f/1;#/+1", the code will become correct. | | What's actually happening is that on Fridays, the "f/1;#/+" | line means "call f, divide the result by 1, and throw away the | result", followed by a comment. On any other day, it means | "call f with the regex parameter /1;#/ and add an unspecified | parameter to it". Since the right hand side of the + operator | isn't specified, it is syntactically incorrect. | hnu0847 wrote: | Why does the following expect arguments: : | sub {}; | | Don't all perl subroutines allow any number of arguments | (including 0) to be passed? | | Does the fact that the above is an anonymous subroutine affect | the answer to my question? | jwilk wrote: | A sub without prototype (anonymous or not) indeed allows any | number of arguments. That's sufficient to trigger the syntax | error. | darrenf wrote: | > _# The following line executes the subroutine "f" and divides | the result by 1 on fridays_ | | > _# but on other days causes the interpreter to trigger a | syntax error_ | | You have this the opposite way round to what's happening (and | the description). It _only_ compiles on a Friday, i.e. when the | sub takes no arguments. | | Removing all the "only on a Friday" stuff boils down to the | difference between these two: # this compiles | sub f() {} f/1;#/+ # this doesn't compile | sub f {} f/1;#/+ | | NB. the latter does compile if you take the `+` off the end, | when it parses to (using -MO=Deparse) sub f | {} f /1;#/; | | When the sub is declared with zero args, `f` can only compile | to mean "call f with no args", thus `/1;#+` means "divide the | return value by one, end statement, rest is a comment". | | However, when the sub _does_ accept args, `f <stuff>` tries to | compile `<stuff>` into arguments to send - and it's a regex | pattern `/.../` so the # isn't a comment, it's part of the | regex, and the + is where modifiers go - but it's invalid, and | is the syntax error. A valid pattern modifier would also | compile, e.g.: sub f {} f/1;#/m | | The argument to `f` here is "whether the pattern /1;#/ matched | against $_": use feature 'say'; sub f | { shift ? "matched" : "unmatched" } $_ = 'this matches | 1;#'; say f /1;#/; $_ = 'this does not match'; | say f /1;#/; | | Which prints: matched unmatched | | So, it turns out the + needn't be characterised as an invalid | modifier after all - it's just addition with a missing second | operand. Add one in and it works as you'd expect: | use feature 'say'; sub f { int shift } | $_='1;#'; say f/1;#/+1 # prints 2 | Sophira wrote: | > You have this the opposite way round to what's happening | (and the description). It _only_ compiles on a Friday, i.e. | when the sub takes no arguments. | | Isn't that what the parent said, going by your quote? They | said "the following line [...] on fridays but on other days | causes the interpreter to trigger a syntax error". | darrenf wrote: | Yes! You're right. Not sure what happened to my brain | there. Too much staring at Perl, I suspect. | metalliqaz wrote: | Thank you for this. I hate trying to read Perl so much. | | What is the "#/+" for? | jwilk wrote: | On Fridays, it's just a comment. | | Otherwise, "f/1;#/+" is equivalent to something like: | f(/1;#/ +) | | where /1;#/ is a regexp matching operator, and stray + | triggers syntax error. | mmaunder wrote: | Worked as a Perl dev for 15 years and enjoyed it. The hardest | thing was the number of ways to do OO Perl using Perl5. | Everyone has their own flavor. And TMTOWTDI was a motto the | community was proud of. | | Having said that, nothing could touch mod_perl performance | under Apache in the late 90s. Massive web apps were built on | this including eToys dot com where I worked before it | imploded in the dot-com bust. | programd wrote: | > Worked as a Perl dev for 15 years and enjoyed it | | Similar situation here. Perl is awsome and I'm still bitter | that Python won. I mean significant whitespace - what great | madness is this??? | | Anyway, yes, mod_perl ran the Web for about a decade in the | early 2000s and I built and maintained huge websites which | were all Perl on the back end. | | BTW the book "Perl Best Practices" by Damian Conway [0] is | the best general programming book I have ever read. Every | software engineer should read it no matter what language | they program in. So much good advice which applies to | pretty much any significant software project. IMHO right up | there with the "Mythical Man Month", though obviously much | more low level. | | [0] https://www.oreilly.com/library/view/perl-best- | practices/059... | tomc1985 wrote: | > Worked as a Perl dev for 15 years and enjoyed it. The | hardest thing was the number of ways to do OO Perl using | Perl5. Everyone has their own flavor. And TMTOWTDI was a | motto the community was proud of. | | One of my frist dev jobs was slinging perl script, I loved | that attitude and it made for a fantastic learning | environment. I really dislike the feeling of having to | write code in a straightjacket because tHe TeAm CaN't | UnDeRsTaNd iT!!! | | We minimized the negatives of TMTOWTDI by incorporating a | house style, but it was flexible because we were all smart | people whose minds didn't crash because we saw a statement | we didn't expect. | space_ghost wrote: | Flavor? "#" starts a comment, so the "/+" characters are | ignored by the interpreter. | [deleted] | G3rn0ti wrote: | > What is the "#/+" for? | | I am sure this is not necessary for the behavior described. | It's just a comment. | | BTW: I am working for a company still maintaining a large | Perl code base and I think this is rather obscure stuff. You | rarely need to run something at compile time, hack the symbol | table and you almost never need "sub() {}" to define | subroutines with an empty "prototype". If I saw this in a | code review I would most definitely had a closer look and | would decline a PR if that was unnecessary. Meta programming | should not be done lightheartedly and better serves a serious | purpose. | pvg wrote: | It's mentioned in the source but it's based on this: | | https://www.perlmonks.org/index.pl?node_id=44722 | jakub_g wrote: | Semi-related HN classic: "Openoffice can't print on Tuesdays" | https://news.ycombinator.com/item?id=8171956 | | A handful of curated weird stories like this: | https://500mile.email/ | gfldex wrote: | As a sister language of Perl, Raku can do the same trick. | constant &s = (now.DateTime.day-of-week == 7) ?? sub () {} !! sub | (|) {}; constant c = s(42); | | Constants are evaluated at compile time. Here we define a sub | that takes no argument or any number of arguments depending on | the day of the week (In Raku we start at 1 for monday to avoid | ending the universe by deviding by 0). While binding the return | value of s(42) to a constant we force execution of that sub at | compile time. Thusly, we create a program that can not be | executed when compiled on sundays. This is reasonalbe, because by | heavenly mandate we are bound to rest on that day. | | Modules are precompiled, programs are not (yet). So to make this | really depend on the day of compilation we have to put it into a | module (for now). | markstos wrote: | Just reading the headline gave me traumatic flashback to a | customer project for a winter sports brand that broke on April | 1st after not being modified for months prior to this. | | You guessed it: There was a sleeper bug detonated by the date | change. Pain the butt to track down in Perl code that was | generating an Excel spreadsheet cell-by-cell. | bastardoperator wrote: | I worked with Randal L. Schwartz for several years in the Los | Angeles area. I was already doing Perl but getting an opportunity | to see his code and ask him questions was something that changed | my career for the better. Thanks Merlyn! | RandalSchwartz wrote: | Have you seen my "parse JSON in a single Perl Regex"? | https://www.perlmonks.org/?node_id=995856 | Drblessing wrote: | What about Phase-Of-The-Moon code? | WesolyKubeczek wrote: | Why only things like these float up to the front page, and not | elegant and/or wholesome things written in Perl? | gerikson wrote: | Perl is like life - it contains both good and bad. | | And good things in Perl don't get noticed because they Just | Work. | JohnHaugeland wrote: | possibly because no such thing exists | sundarurfriend wrote: | Because with its declining popularity, most people here are | unfamiliar with the language except for its meme status as | "that weird line noise language". Things that confirm pre- | existing beliefs are easy to accept and upvote, whereas good | Perl code would require (a) some actual thinking, and (b) | challenging the socially accepted narrative - both of which are | relatively much harder. | WesolyKubeczek wrote: | Good Perl code would also look pretty boring, almost like | enterprise Java. | | I'd wager that all code that "just works", in any language, | looks bland and predictable. | | But I'd rather have that than cute and clever any day. | anthk wrote: | Good Perl looks like a mix between structured SH and a | dumbed down C with no pointers. Boring, as you say. But it | works. | kqr wrote: | Afaik Perl is not declining in popularity, it's just not | growing in popularity as fast as many other languages, so | it's market share shrinks while the number of users it has | grows. | anthk wrote: | True, most Gen-Z ers know nil. | | First they should try Perl as if it was a tuned up AWK, and | then, read the Orelly Perl books as if they were a religion. | | https://docstore.mik.ua/orelly/perl4/index.htm | layer8 wrote: | Right, it's elegant Perl that would be newsworthy, not gruesome | Perl. | | (Tongue-in-cheek, I'm actually rather partial to Perl.) | lanstin wrote: | I loathe perl still (based on having to SSH (or telnet?) into | people's systems and debug their perl scripts in the 90s) but, | Higher Order Perl, https://hop.perl.plover.com/ is a truly | excellent introduction to the power of functions that generate | functions, more accessible and more immediately useful than | Paul Graham's On Lisp. The lessons are immediately applicable | at least to Javascript and Python. Strongly typed things like | Go make it a bit more work, but still you'll understand why the | work is worth doing. | alkaloid wrote: | Someone found my telco code. | fouronnes3 wrote: | Pro tip: add test cases to your CI runs with modified system | date. | WesolyKubeczek wrote: | The thing is, you need to have a pretty corkscrew mind to think | about cases like this. | | What date to change to? Far into the future? Far into the past? | To a weekend? To a DST change? To Friday the 13th? To a US | holiday? To a Muslim, Jewish, Chinese, Soviet, Albanian | holiday? To a particular weekday? To Hitler's birthday? What if | it's Lenin's? To that one day my coworker was depressed because | the boss denied him a raise and talked shit to him? Too many | possibilities. And your timebomb might be in one of your | dependencies to boot. | zanderwohl wrote: | I feel obligated to link "Falsehoods programmers believe | about time" - I think it's best to just get a trusty library | instead. https://gist.github.com/timvisee/fcda9bbdff88d45cc90 | 61606b4b... | JohnBooty wrote: | Amen. | | Worked for a few years at a company with a medium-sized | codebase whose tests only worked before 6PM. | | (Run the tests later than that, and you wind up with some | timeframes that span calendar days and therefore break things. | Was the underlying code broken, or the tests, or both? Who | knows!!) | | Was never allowed to fix and investigate. Or to be specific, we | were never given the time to fix it. Management simply didn't | see it as a problem. | | In my younger days I would have gone all HERO HACKER and fixed | it anyway on my own time. But now, I know how that turns out. | You waste a bunch of evenings fixing it, and usually introduce | some other regressions, and you get zero glory and lots of | blame. Best case scenario is no regressions and zero glory. | | So, screw it. Old-and-jaded me never lifted a finger. If the | company doesn't care, why should I? | | But, that is an excellent protip. If you are working on a team | that actually values things that work. Time/date dependent code | is _very_ tricky to get right, especially when multiple time | zones are involved. If your test suite doesn 't cover multiple | possibilities, your code is nearly guaranteed to be wrong. | | It's not even like you have to write brand-new, cleverer tests. | Just "brute-force" it, assuming your tests are performant: | | before: some_tests | | after: [time_zone_1, time_zone_2, | time_zone_3].each do |tz| [time_of_day1, | time_of_day2, time_of_day3].each do |tod| | some_tests(tz, tod) end end | | ...that kind of thing. That's what I did when I wrote new code | at that company, even though I refused to fix the legacy stuff. | My tests were faster, too. Almost like I knew what I was | doing... | janekm wrote: | Was it a German company? If so "you can only do work during | working hours" would be considered a feature not a bug ;) | [deleted] | raxxorrax wrote: | I have written code that only works in winter because of daylight | saving times and some unfortunate date conversions, but having a | temporary correct syntax is really a new high. | profmonocle wrote: | The first iPhone app I wrote back in college would crash if you | used it in a time zone with a positive UTC offset. I can't even | remember why. | nicoburns wrote: | > I have written code that only works in winter because of | daylight saving times and some unfortunate date conversions | | Not sure where you are located, but this can be particularly | bad in the UK where winter time happens to coincide with UTC. | DocTomoe wrote: | Let's be pedantic about this, because this is one of the very | few areas where pedantry matters: GMT ("British Winter Time") | is NOT UTC, and it can differ from UTC up to 0.9 seconds. GMT | is a time zone (corresponding to UT1). UTC is a time | standard. | dane-pgp wrote: | I appreciate your pedantry, and I wonder if you know of a | widely used computer system which genuinely implements the | GMT time zone as something different from UTC+0. | | There may be some niche astronomical or legal(?) | applications which have to keep track of the potential 0.9 | seconds skew, but my impression is that any app which | claims to support a "GMT" (or Europe/London) option is | actually only supporting "GMT-ish". | Dylan16807 wrote: | > GMT is a time zone (corresponding to UT1) | | Are you sure? Looking into things I would have said that | GMT exists as a time reference but all the time _zones_ are | based on UTC. | jfk13 wrote: | To be pedantic, this is an area where pedantry | _occasionally_ matters. For the vast majority of (casual) | usage, it doesn 't. | gerikson wrote: | Indeed. I get invites from people from the UK who simply | refer to the current local time (GMT or BST) as "GMT". It | just means current London time to them. | ycombobreaker wrote: | Same happens in the US, people use EST/EDT | interchangeably (and incorrectly) when they mean Eastern | timezone. Or Central/Mountain/Pacific. | nicoburns wrote: | Ok, fair enough. But it's close enough that it's very easy | for anything that isn't working with second-level | granularity to seem like they're working only to break as | soon as the time switches BST. | hughrr wrote: | Yeah it's horrible. I had a contract a number of years ago to | fix a bug that they had been fighting for 5 years. When | winter time kicked in all appointments on their booking | system collapsed to zero minutes long. | | To fix this they ran a SQL script that changed the end date | on the DST switch over but that had some poor assumptions in | it and made it worse. | | It also had to be correct in the past and the future. | | I just rewrote the whole fucking thing from scratch. | hyperman1 wrote: | As a part of a release always got borked, I wrote a small bash | script that took currently deployed files, archived them to | rollback_dateandtime.tgz, then put the freshly released files | in its place. | | It turns out we never did a release before 10:00, because it | ran fine for a few years, but the regex constructing the | filename could not deal with hours consisting of 1 number. | | Oh well, never write production shell scripts while your | platform is burning. | | The fix is literally 1 character, but I only get access when | production burns. So I was not allowed to change it and the | owner does not want to implement it and file all release | paperwork it entails. Instead, mgmt forbid this type of release | before 10:00. | gpvos wrote: | This is why we can't have nice things. | chaosite wrote: | I have written code (at work) that crashes when the moon is in | a specific phase. | | I had a "switch(moon_phase)" and forgot one of the cases... And | the Android app was in debug mode, so any uncaught exception | brought the whole thing down. | grishka wrote: | Not nearly as cursed as two parent comments, but there was a | widespread problem in my very popular Android app. The | relative date formatting function worked incorrectly for many | users, it was off by one hour. It turns out that when Russia | (where most of our users were) had abolished DST, and then | changed timezones a couple of times, people got really | confused. Since Android's timezone data is part of the | system, it was basically set in stone. Most of the users | didn't choose the timezone with the correct offset, but | instead set their time an hour forward so the incorrect | timezone and incorrect unixtime cancel each other out for a | "correct" displayed time. | | I ended up getting the known correct unixtime from the server | to try to guess which timezone offset the user _actually_ | meant and correcting the result of System.currentTimeMillis() | and my formatting for that. | tupac_speedrap wrote: | Having the code crash every full moon would be pretty cursed | tbh. | dotancohen wrote: | I have once heard of some software that would crash on some | Wednesdays. Apparently Wednesday is the longest day name, and | it was overflowing some buffer. But only if the day of the | month was 10 or above, because the strings 1-9 still fit in the | buffer. ___________________________________________________________________ (page generated 2022-02-16 23:00 UTC)