1 पॉइंट द्वारा GN⁺ 3 시간 전 | 1 टिप्पणियां | WhatsApp पर शेयर करें
  • Elixir के guard में or conditions का क्रम बदलने भर से, एक जैसे logical expression जैसा दिखने वाले code का result बदल सकता है
  • is_integer(x) or is_map_key(x,:foo) क्रम में integer input पर short-circuit evaluation पहले हो जाती है और risky check skip हो जाता है
  • इसके उलट is_map_key(x,:foo) or is_integer(x) में integer input पर पहला condition false लौटाने के बजाय fail हो जाता है, इसलिए दूसरा condition evaluate ही नहीं होता
  • इसी फर्क की वजह से Foo.a(%{foo: 21}), Foo.a(37), Foo.b(%{foo: 21}) तो true हैं, लेकिन Foo.b(37) false बन जाता है
  • यह boolean operation के commutative law के टूटने जैसा लग सकता है, लेकिन short-circuit evaluation वाले or में condition order का असर स्वाभाविक है, और Elixir 1.20.1 व OTP 29 के आधार पर कोई warning नहीं दिखती

condition order से result बदलने का उदाहरण

  • example module Foo में a/1 और b/1 दो functions define किए गए हैं
    • a/1: guard को is_integer(x) or is_map_key(x, :foo) क्रम में check करता है
    • b/1: guard को is_map_key(x, :foo) or is_integer(x) क्रम में check करता है
    • guard match होने पर true, नहीं तो अगले clause में false return होता है
  • a/1: जब safe condition पहले आती है

    • Foo.a(%{foo: 21}) true बनता है
      • is_integer(x) false है
      • is_map_key(x, :foo) true है
      • or का result true होने से पहला clause match हो जाता है
    • Foo.a(37) भी true बनता है
      • is_integer(x) true है
      • or की short-circuit evaluation होने से is_map_key(x, :foo) execute नहीं होता
  • b/1: जब fail हो सकने वाला condition पहले आता है

    • Foo.b(%{foo: 21}) true बनता है
      • is_map_key(x, :foo) true है
      • बाद वाला is_integer(x) execute नहीं होता
    • Foo.b(37) false बनता है
      • पहला condition is_map_key(x, :foo) false return करने के बजाय fail हो जाता है
      • guard function का fail होना false में convert नहीं होता, बल्कि पूरे guard expression को fail कर देता है
      • बाद वाला is_integer(x) call नहीं होता और पहला clause भी match नहीं करता

short-circuit evaluation और warning का न होना

  • कई Elixir developers को यह behavior boolean operator के commutative law के टूटने जैसा लग सकता है
  • लेकिन or short-circuit evaluation करता है, इसलिए दोनों conditions की जगह बदलने पर हमेशा एक जैसा result आएगा, ऐसा मानना सही नहीं है
  • संदर्भ environment Elixir 1.20.1, OTP 29 है, और इस issue पर Elixir कोई warning नहीं देता, ऐसा दिखता है

1 टिप्पणियां

 
GN⁺ 3 시간 전
Lobste.rs की राय
  • मैं Elixir प्रोग्रामर नहीं हूं, लेकिन आखिरी उदाहरण में सबसे चौंकाने वाली बात यह है कि guard expression की error caller तक propagate नहीं होती, बल्कि वह guard “skip” हो जाता है।
    मुझे लगता है समझ में आता है कि इसे ऐसा क्यों बनाया गया, लेकिन यह भी हैरानी की बात नहीं कि इससे intuition के उलट नतीजे निकलते हैं।

  • यह सोचें तो irony है कि Erlang का API design Armstrong की Erlang thesis p109/s4.5 में बताई गई intentional programming में मदद करने के लिए था।
    thesis में dict:fetch(Key, Dict), dict:search(Key, Dict), dict:is_key(Key, Dict) जैसे functions को अलग-अलग समझाया गया है, जो programmer का intent दिखाते हैं: “key जरूर होनी चाहिए”, “हो भी सकती है इसलिए flow अलग करें”, और “सिर्फ मौजूदगी check करनी है।”
    लेकिन Elixir का is_map_key/2 अगर “dict” argument dict नहीं है तो exception देता है, और वह exception failure पूरे guard clause की failure में बदल जाता है, जिससे यह distinction टूटती हुई लगती है।
    उल्टा, अगर कोई भाषा ऐसी हो जहां or exception को पकड़कर false में मिला दे, तो शायद दूसरे cases में वह और भी ज्यादा चौंकाने वाला लगे।

  • पहले देखी गई इस चर्चा की वजह से मैं इस quiz को हल करने के लिए तैयार था, और तब मैंने कुछ चीजें सीखी थीं।

    • उसी चर्चा से प्रेरित होकर यह लेख लिखा गया।
  • सीखने को मिला, लेकिन यह अफसोस रहा कि Pratchett reference से क्यों बचा गया।
    Death कहीं न कहीं अपना माथा पकड़ रहा होगा।
    यहां दो दिलचस्प बातें हैं: false नहीं, बल्कि failed guard पूरे expression को fail करा देता है; और थोड़े non-intuitive तरीके से is_map_key, is_map check को अपने अंदर include नहीं करता।
    is_map(x) and is_map_key(x, :corporal) जैसा तीसरा variant जोड़ें तो यह उम्मीद के मुताबिक काम करता है।
    is_map_key का behavior थोड़ा inconsistent लगता है और इसलिए surprising महसूस होता है; बाकी is_... guards में से कौन safe हैं और किनमें type expectation मानकर evaluation करनी पड़ती है, यह check करना दिलचस्प होगा।

    • Pratchett reference पर सहमत हूं, लेकिन अभी heatwave चल रही है, इसलिए दिमाग उम्मीद के मुताबिक काम नहीं कर रहा।
    • जिज्ञासा में मैंने खुद कुछ चीजें check कीं, और मोटे तौर पर लगता है कि is_map_key ही एकमात्र is_ guard है जिसे किसी खास तरह का argument चाहिए।
      बाकी is_ functions boolean nature रखते हैं और हमेशा true | false लौटाते हैं, fail नहीं होते।
  • यहां एक दिलचस्प Elixir style सवाल उठता है।
    उदाहरण मजेदार है और explanation भी अच्छी है, लेकिन व्यक्तिगत रूप से मैं जहां संभव हो guards के बजाय pattern matching को prefer करता हूं।
    बेशक exceptions हैं, पर ऐसे functions मैं आमतौर पर कई function clauses के रूप में लिखता, जैसे def a(%{foo: _x}), do: true, def a(x) when is_integer(x), do: true, def a(_), do: false

  • साथ में देखने लायक: https://learnyouahaskell.github.io/syntax-in-functions.html/…

    • Haskell के guards थोड़े अलग हैं।
      Haskell में guard के अंदर arbitrary function call कर सकते हैं, लेकिन Erlang उसमें allowed functions के set को restrict करता है।