{"action":"opened","issue":{"url":"https://api.github.com/repos/hylang/hy/issues/842","labels_url":"https://api.github.com/repos/hylang/hy/issues/842/labels{/name}","comments_url":"https://api.github.com/repos/hylang/hy/issues/842/comments","events_url":"https://api.github.com/repos/hylang/hy/issues/842/events","html_url":"https://github.com/hylang/hy/issues/842","id":95114676,"number":842,"title":"Conditionals waste assignments.","user":{"login":"gilch","id":3346292,"avatar_url":"https://avatars.githubusercontent.com/u/3346292?v=3","gravatar_id":"","url":"https://api.github.com/users/gilch","html_url":"https://github.com/gilch","followers_url":"https://api.github.com/users/gilch/followers","following_url":"https://api.github.com/users/gilch/following{/other_user}","gists_url":"https://api.github.com/users/gilch/gists{/gist_id}","starred_url":"https://api.github.com/users/gilch/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/gilch/subscriptions","organizations_url":"https://api.github.com/users/gilch/orgs","repos_url":"https://api.github.com/users/gilch/repos","events_url":"https://api.github.com/users/gilch/events{/privacy}","received_events_url":"https://api.github.com/users/gilch/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":0,"created_at":"2015-07-15T06:04:34Z","updated_at":"2015-07-15T06:04:34Z","closed_at":null,"body":"Conditionals containing statements are doing unnecessary work. I know, Python is not renowned for its performance, but let's not make it worse. This kind of thing can matter inside nested loops.\r\n\r\nCurrently a `cond` like this:\r\n```\r\n(cond [0 \"zero\"]\r\n      [1 \"one\"]\r\n      [True (assert 0)])\r\n```\r\nTurns into this:\r\n```\r\nif 0:\r\n    _hy_anon_var_3 = 'zero'\r\nelse:\r\n    if 1:\r\n        _hy_anon_var_2 = 'one'\r\n    else:\r\n        if True:\r\n            assert 0\r\n            _hy_anon_var_1 = None\r\n        else:\r\n            _hy_anon_var_1 = None\r\n        _hy_anon_var_2 = _hy_anon_var_1\r\n    _hy_anon_var_3 = _hy_anon_var_2\r\n```\r\nBut wouldn't it would work just as well like this?\r\n```\r\nif 0:\r\n    _hy_anon_var_1 = 'zero'\r\nelif 1:\r\n    _hy_anon_var_1 = 'one'\r\nelif True:\r\n    assert 0\r\n    _hy_anon_var_1 = None\r\n```\r\nHalf the assignments for the same effect. And the `hy --spy` output is much more readable. I don't think CPython can automatically optimize this kind of thing. I know not all of them happen for any given branch, but the deeper ones will still do more assignments than they should.\r\n\r\nPython has no switch/case. Sometimes you can get away with dictionary lookups instead, but if you need side effects or performance, you're supposed to use cascading `elif` where you would have used a switch. \r\n\r\nCurrently there's no `elif` form in Hy. `cond` is the closest we've got. Now I could write nested `if`s instead (or a macro to do it for me) but look at what it turns into:\r\n```\r\n=> (if 0 \"zero\"\r\n... (if 1 \"one\"\r\n...       (assert 0)))\r\nif 0:\r\n    _hy_anon_var_2 = 'zero'\r\nelse:\r\n    if 1:\r\n        _hy_anon_var_1 = 'one'\r\n    else:\r\n        assert 0\r\n        _hy_anon_var_1 = None\r\n    _hy_anon_var_2 = _hy_anon_var_1\r\n```\r\nNot quite as bad as the `cond` since we have a final `else`, but still twice what is necessary:\r\n```\r\nif 0:\r\n    _hy_anon_var_1 = 'zero'\r\nelif 1:\r\n    _hy_anon_var_1 = 'one'\r\nelse:\r\n    assert 0\r\n    _hy_anon_var_1 = None\r\n```\r\nMaybe it's too hard to optimize nested `if` forms like that? Is `cond` defined in terms of Hy's `if` form in the first place? I didn't implement `cond` but you could totally do it as a macro in terms of `if`.\r\n\r\nWhy not extend Hy's `if` to work like Arc Lisp's (as I proposed in #830 ), which can accept two or more arguments:\r\n```\r\n=> (if a b)\r\nif a:\r\n    _hy_anon_var_1 = b\r\nelse:\r\n    _hy_anon_var_1 = None\r\n=> (if a b\r\n         c)\r\nif a:\r\n    _hy_anon_var_1 = b\r\nelse:\r\n    _hy_anon_var_1 = c\r\n=> (if a b\r\n       c d)\r\nif a:\r\n    _hy_anon_var_1 = b\r\nelif c:\r\n    _hy_anon_var_1 = d\r\nelse:\r\n    _hy_anon_var_1 = None\r\n=> (if a b\r\n       c d\r\n         e)\r\nif a:\r\n    _hy_anon_var_1 = b\r\nelif c:\r\n    _hy_anon_var_1 = d\r\nelse:\r\n    _hy_anon_var_1 = e\r\n```\r\netc., for any number of inner `elif`s you need.\r\n* Now you only have to generate AST for the new `if` form, instead of optimizing nested forms. \r\n* It make Hy's `if` act more like Python's cascading `elif`.\r\n* This doesn't break existing Hy code, since we're not using more than 3 arguments now, and the 2 and 3 argument cases work exactly like before. \r\n* `cond` can be redefined in the same way, and get the same benefits."}}