論理否定の優先順位No.31580
uchino さん 12/10/15 14:21
 
いつもお世話になっております。
論理演算子の否定「!」について、教えてください。

二項演算と単項演算子を同時に使用すると、エラーが発生します。
たとえば以下のように2つの真偽値を評価したい場合です。

if (#bool1 && !#bool2) {}

エラー:数値が指定されるべきところに数値以外のものが指定されています。

順番を変えたりカッコを付けると、以下のようになります。

if (!#bool2 && #bool1) {} // エラーではないが意図と違う結果
if (#bool1 && !(#bool2)) {} // ERROR
if (#bool1 && (!#bool2)) {} // OK

ということは単に優先順位の問題かな?と思いヘルプを見ると「C言語と異なるので
注意」と書かれていますが、しかしよく解らないのは、結合規則で言えばC言語や他
言語でも論理否定は単項演算子ですから右しか対象にしないはずと思いますが、右全
体を評価しているように見えるのと、「&&」の右にあると、つまり「&&」より後に評
価される(?)ためか「#bool1 && !」という式を先に評価しようとしてエラーにな
るのか(エラーメッセージが言う「数値以外」とは「!」のこと?)、という点です。

そもそもヘルプに載っている表の見方がちょっと解らないんですが…^^; 左が高いの
は良いとして、縦方向が解りません。
上が高いという意味にも見えるところもありますが(&&と||)、そうでないところも
あります(*と/)。
結合規則が良く解らないと言いますか、これもCなどと違うのでしょうか。

そして結局のところ、「#bool1が真かつ#bool2が偽」としたい場合は
if (#bool1 && (!#bool2))
と書くのが正解でしょうか。

[ ]
RE:31580 論理否定の優先順位No.31581
秀まるお2 さん 12/10/15 14:34
 
 すみません。これは、しいて言うとバグなんですが、マクロの互換性が壊れて
しまうとまずいって問題があって、そのまま直さずに置いていたりします。

> そして結局のところ、「#bool1が真かつ#bool2が偽」としたい場合は
> if (#bool1 && (!#bool2))
> と書くのが正解でしょうか。

 現状、そのように書いていただくしか無いようです。

 if( ! xxx && ! yyy )

 とかの場合なら、

 if( (! xxx) && (! yyy) )

 としていただければ間違いないです。

> if (!#bool2 && #bool1) {} // エラーではないが意図と違う結果

 実はこれが互換性の問題になってしまうのですが…。

 カッコで囲んでなければ警告(マクロ実行中にエラー?)を出すようにしつつ、
ヘルプに「!と他の演算子を組み合わせる場合はカッコで囲んでください」って
書いた方がいいかもしれません。

 なんとか対策を考えますので、とりあえず現状はカッコで囲むということでお
願いします。

[ ]
RE:31581 論理否定の優先順位No.31586
秀まるお2 さん 12/10/15 19:21
 
 「!」と「||」や「&&」の優先順位を別にする処理も試しに作ってみたんです
が、こうしてしまうと、やはりマクロの互換性に問題が出るような気がします。

 なので、優先順位を変更するのはやはりやめておきます。

 代わりに、

  if( ! #a || #b )
  if( #a || ! #b )

 のように「!」と他の「||」や「&&」を同一レベルで混ぜて使った場合には、
警告メッセージを出すようにします。警告メッセージからヘルプも呼び出せるよ
うにします。

 さらには、もしもマクロを手直しするのが難しいユーザー様もおられると思う
ので(ライブラリからダウンロードしたマクロをそのまま使ってる場合とか)、
「動作環境・トラブル対策・その他のトラブル対策」の中に、


    マクロで「!」と「||」、または「!」と「&&」を並べて使っても警告を出さない


 ってオプションも追加することにします。

 現状ではそういう対策しか無いかなぁと思います。
 (やはりマクロの互換性を壊すのは良くないと思うので…)

[ ]
RE:31586 論理否定の優先順位No.31592
uchino さん 12/10/16 11:17
 
ご回答ありがとうございます。
なるほど互換性の問題は大きいですね。いずれにしても、意味不明でモヤモヤしてい
たのがスッキリしました。

(!#bool2 && #bool1) という書き方は、慣例的に何の疑いもなしに書いてしまうもの
で、偶然今回は右が否定だったためにエラーが発生したことで私は気づいたから、む
しろラッキーでした。
エラーが発生することもなければ、気づかずに潜在的なバグコードを書いてしまって
いる人も多いような気がします。
しかし、このことが解ってさえいれば、ただカッコで囲むだけなら違和感も小さいで
すから、ぜひとも警告とヘルプをお願いします。
見たところ単項演算子は「!」だけのようですし、これだけ特別扱いすれば、さほど
特殊性もないように思います。

それと、ヘルプの優先順位の表ですが、縦方向はどうなりますか?
今回の「!」の列だけ見れば「上が高い」ようですが、「+」と「-」は同列でしょう
し、しかし「|」と「&」についても記載があると言うことは、これも特殊で、そして
ここは「上が高い」になるのでしょうか。


[ ]
RE:31592 論理否定の優先順位No.31593
秀まるお2 さん 12/10/16 11:41
 
> し、しかし「|」と「&」についても記載があると言うことは、これも特殊で、そして
> ここは「上が高い」になるのでしょうか。

 &&と||も、実は秀丸マクロとC言語で結果が違ってまして、例えばC言語では、

   if( a && b || c && d )

 は、

   if( (a && b) || (c && d) )

 相当になります。

 秀丸マクロの場合は、単純に左から右に評価していくだけでして、例えば

    #a = 1;
    #b = 0;
    #c = 0;
    if( #a || #b && #c ) {
        message "true";
    }

 は、まず#a || #bが評価されて結果が1となりますが、そのあと

    1 && #c

 相当の評価がされて、結果0になってしまったりします。

 単純に左から右に計算していってるだけだったりします。

 この注意点についても昨日ヘルプに書いた所でしたが、これもマクロ実行時に
警告を出す方がいいかもしれないと思いつつ、とりあえずやめました。

 ややこしくてすみません。

[ ]
RE:31593 論理否定の優先順位No.31594
uchino さん 12/10/16 14:17
 
そうだったんですか…、今まで気にせず(&&が上のつもりで)ずっと書いていました
…。
時間を見つけて過去のコードを見直してみます。

この件は「!」よりも大きいような気がします。
C系の文法と似ているので、しかもヘルプの表はパっと見では「だいたい普通」に見
えてしまうので、慣れた文法で書いてしまいます。

そうしますと、表の見方は、本当に単純に「左から右へ」高低なんですね。縦方向の
並びには意味が無く、「&&」が上にあるのもたまたま、というわけですね。

すると先の「!」がエラーになったのも、てっきり「&&」より低いからだとか結合規
則が特殊どうこうとか思っていましたがそうではなく、単に「左から順番に評価し
た」だけの結果だったのですね。今ごろ解りました^^;
本当に偶然エラーになってくれて見つかったわけですね。

私としては、これはぜひともヘルプには記載すべきと思いますが、いかがでしょうか。
何度も恐縮ですが、やはりあの表は解りにくい…、というか他言語のリファレンスや
入門書などでよく見るお馴染みの表に形が似ていて、でも実は意味が微妙に違う、と
いう点で誤解しそうです。私は完全に誤解していましたし…。
そしてやはり論理演算子はロジックに影響しますから大きいと思います。エラーにも
ならない場合は潜在的バグの原因にも。

警告は難しそうですね。実行時に表示するわけですよね?
「!」だけなら、条件式の中で他の演算子と一緒かつ左にあったらミスの可能性が高
い(右にあればエラーなので不要)、と、かなり絞られますが、「&&」と「||」を一
緒に使っただけではミスなのかどうか不明で、それで警告が表示されてしまう。
本来なら開発者に対して警告すべきですし。

一般的な開発環境では、こう言う場合はコーディング時にエディタ上にツールチップ
で警告されたりしますが、この考え方で、強調表示で何とかなりませんかね?
ファイルタイプがマクロの場合、if文などの条件式の中で同レベルの演算子が混在し
ていたら赤太字で表示、というように。
ツールチップが一番良いですが、とりあえず異変には気づきます。
どうでしょう。

[ ]
RE:31594 論理否定の優先順位No.31596
秀まるお2 さん 12/10/16 15:20
 
 実は秀丸エディタや秀丸メールのソースコードでも、||と&&の優先順位につい
ての解釈があいまいなせいでバグが入り込んだ所がありまして、&&と||をまぜる
時は、僕の所では必ずカッコで囲むようにしています。

 あと、||と&&を混ぜて使ってる所があるかどうか調べる用の秀丸マクロもあっ
たりします。(秀丸担当が作りました)

> 私としては、これはぜひともヘルプには記載すべきと思いますが、いかがでしょう
>か。

 実は今回の話の関係があって、それについてもヘルプには追加記述はしました。

> ツールチップが一番良いですが、とりあえず異変には気づきます。
> どうでしょう。

 マクロの文法をリアルタイムでチェックしてツールチップを出すってのは、ほ
とんど不可能に近いくらい難しいです。そもそもそういう機能を作ったとしても、
マクロを書いてる時にユーザーさんがその機能をONにしてくれないとダメだし。

 実行時に警告を出す以外には、マクロを読み込んだ段階(内部的なコードに変
換した段階)でエラーを出すくらいは出来るかと思いますけども、とりあえず実
行時に出す方が簡単なのでそうした所でした。

 果たしてどうしたらいいか難しいですが、とりあえずは実行時に出す警告の方
で、!と||を混ぜた、あるいは!と&&を混ぜた以外にも、&&と||を混ぜた場合も警
告を出すようにするのが一番簡単です。

 とりあえずβ版ということで、一回そういう仕様で出してみようかと思います。
それであちこち警告が出まくるようなら、また何か対策を考えたらいいかなぁと
いう風に思います。

[ ]
RE:31596 論理否定の優先順位No.31597
秀まるお2 さん 12/10/16 15:54
 
 実行中(&& || !の混在文を処理した瞬間)にエラーを出すのやめて、マクロ
を読み込む時に警告を出すようにします。

[ ]
RE:31597 論理否定の優先順位No.31602
uchino さん 12/10/17 01:18
 
なるほど、とりあえずは、やはり警告が妥当のようですね。
ツールチップというのは、あくまでも他の開発環境での「たとえ話」でして、実装は
難しそう以前に秀丸エディタは役割も違いますし(テキストエディタの範疇外)、む
しろ邪魔のように思います。
で、ツールチップ的な位置づけ、ようするにコーディング中にプログラマに知らせる、
という目的から考えれば、強調表示で何とかなるのでは?と考えた次第です。
と、そうは思ったものの、考えてみれば評価式なんてifやwhileだけじゃなく、あら
ゆる式に出てきたりしますし、これはこれで難しそうですね…。

私は秀丸エディタは95年頃から使わせていただいておりますが、先ほどざっと過去
に書いたマクロを調べてみたら、やはりこの件でバグってる疑い…の怪しげな箇所が
いくつか見て取れて、もう見なかったことに…^^;
もちろんマクロですから大がかりなシステムなど組むはずもなく、重大な問題になら
ないように思いますが、しかしその反面、手軽さ故にちょっとした作業でもすぐ適当
なマクロを書いてしまう、ということを続けて来ました。
今思えば、相当な数がバグってたのかもしれませんね…。逆に、何か重大な問題にな
らずに今まで来られたのはラッキーです。何せまったく気づかなかったぐらいですか
ら^^;

とりあえず警告が表示されれば、それでこの問題に初めて気づく人もおられるでしょ
うから、その点では効果的だと思います。ただ私も含めすでに知った後の人にとって
は、逆に邪魔になる可能性もありますね。かといってオフにして良いか迷いそうです。
本当の意味で根本的な解決方法は、そもそもこういう仕様であると、明示して周知す
る、ということとも言えると思います。
つまり「この言語は、式で優先する部分はカッコで囲むもの、これが常識」と最初か
ら解っていれば、そのつもりで書き警告も不要と言えると思います。
回りくどい言い方をしていますが…、やはりヘルプは重要だと思いますので、今回対
応していただけるなら、むしろ警告よりこちらのほうが重要かもしれません。

[ ]
RE:31602 論理否定の優先順位No.31628
秀丸担当 さん 12/10/18 09:33
 

参考までに、if( a && b || c )といったような書き方をしているところを一覧
表示するマクロをちょっと前作っていたので書いておきます。

−−−−−−−−−

//演算子チェックマクロ
//「if( a && b || c )」のような書き方をしている部分をチェック
//します。現在のフォルダ内の該当するファイルをチェックしてgrep風
//の出力を出します。

$targetfiles = "*.mac;*.cpp;*.c;*.h";

//-----------
disablehistory 0x7f;
$s=searchbuffer;
#s=searchoption;
setclipboard "";
closenew;
grep ".",$targetfiles,".",regular,filelist;
#ifile=0;
#cfiles=linecount2;
#hgrep=hidemaruhandle(0);
#chit=0;
while(1){
    setactivehidemaru #hgrep;
    if(#ifile>=(linecount2-1))break;
    moveto2 0,#ifile;
    tagjump;
    gofiletop;
    disabledraw;
    disableerrormsg;
    while(1){
        searchdown "(if|while|for)",word,regular;
        if(result==false){
            break;
        }
        escape;
        moveto foundendx,foundendy;
        searchdown2 "(";
        if(result==false){
            break;
        }
        if(tickcount>#ticknext){
            #ticknext=tickcount+1000;
            title str(lineno)+"/"+str(linecount2) + "line "
             + str(#ifile+1)+"/"+str(#cfiles)+"file";
        }
        escape;
        #xtop=x;
        #ytop=y;
        gokakko;
        #xend=x;
        #yend=y;
        moveto #xtop,#ytop;
        #cAnd=0;
        #cOr=0;
        while(1){
            searchdown "&&|\\|\\||\\(",regular;
            if(result==false)break;
            if(y>#yend)break;
            if(y==#yend&&x>#xend)break;
            if((colorcode & 0x1F)==3)continue;
            escape;
            moveto foundtopx,foundtopy;
            if(code==0x26){ //&
                #cAnd=#cAnd+1;
            }else if(code==0x7c){   //|
                #cOr=#cOr+1;
            }else if(code==0x28){   //(
                gokakko;
                if(y>#yend)break;
                if(y==#yend&&x>#xend)break;
            }else {
                break;
            }
        }
        if( ((#cAnd+#cOr)>=2 && #cAnd>0 && #cOr>0)
         || (#cEqual>0) ){
            moveto #xtop,#ytop;
            addclipboard basename2+"("+str(lineno)+") : "
                + gettext(0,#ytop,linelen,#ytop)
                +"\n";
            #chit=#chit+1;
        }
        moveto #xend,#yend;
    }
    #hclose=hidemaruhandle(0);
    setactivehidemaru #hgrep;
    closehidemaru #hclose;
    #ifile=#ifile+1;
}
setsearch $s, #s;
newfile;
if(#chit>0){
    paste;
} else {
    insert "該当なし\n";
}
clearupdated;
gofiletop;
closehidemaru #hgrep;

[ ]
RE:31628 論理否定の優先順位No.31629
uchino さん 12/10/18 11:11
 
ありがとうございます。助かります。

ところで、互換性の件ですが、今まで通りの評価を行う「互換モード」と、Cなど一
般的な言語と同じように評価を行う「標準モード」を、切り替える機能を実装する、
というのはどうでしょうか。
ブラウザがHTMLの解釈を切り替えるのと同じ発想です。

たとえばマクロの先頭に
//@general
と書いておくと標準モードとして実行し、そうでなければ互換モード、旧バージョン
の秀丸エディタはコメント行として無視するので影響しない=互換モードとなる。

あるいは、拡張性とか、もし将来的に似たような事例が発生した場合などに対応でき
るように、
//@require 8
標準モードかつバージョン8以上でしか動かない(新機能を使っている)マクロであ
ることを宣言するとか。

できれば両方とも実装していただければ、私のような、今まで優先順位を誤解して書
いてきてしまった人は、過去に書いたマクロはすべて「//@general」を入れるだけで
解決します。
そして利用者側は何もしなくて良く、警告に驚くこともないと思います(マクロを利
用するのみで書かない人にとっては、警告は意味不明で不安にもさせてしまう)。
どうでしょう。

[ ]
RE:31629 論理否定の優先順位No.31632
秀まるお2 さん 12/10/18 12:13
 
 実は秀丸マクロでは、互換性に関係する機能拡張をしてもなんとか互換性を維
持する目的で、setcompatiblemodeって命令があるにはあります。なのでこれを
使って「!」の動作を正しくすることも可能ではあります。

 &&と||をカッコで囲まずに並べて使うのは、個人的にはそもそもそういうこと
自体がバグの温床だと思ってるのであんまり使わない方がいいんじゃないかとい
う気がします。

 「!」については、もし他のユーザー様からもなんとかして欲しいって話があ
るならsetcompatiblemodeで対応しようかなぁと思いますけども、正直、もう2
0年近く同じ仕様でやってきたので、今さらって気はします。

 V8.22βの方で、一応、ちゃんと警告は出るようになってますので、それでほ
とんど大丈夫かなぁという気がします。(しょせんエディタのマクロだしっての
もあるし…)

[ ]
RE:31632 論理否定の優先順位No.31635
uchino さん 12/10/18 14:09
 
確かに。
まぁ妥協という意味では、それこそヘルプでの明示で十分かもしれませんね。率直に
言えば、むしろこれこそが原因でもあったように思います。

警告で懸念されるのは、開発者にも利用者にも無差別に警告してしまうことで、マク
ロを配布している人は注意や対応が必要でしょうし、自分で書かない人は突然の意味
不明な警告に驚いて、すでに開発者がサポートしていないマクロを使っている人は、
御社のほうに問い合わせるかもしれず、その対応とか、この点でも(マクロのではな
い)ヘルプにも注意書きが必要とか、ある程度の影響はあるような気がします。
そのあたりは私などが心配してもしょうがないですが…。

今さら感についてもっと言えば、この件に私は20年近く気づかなかったわけで、運良
く、いや運悪く今までエラーに遭遇しなかったためで、これこそ、え、なんで今さら
…、という感じです(苦笑)。
私だけなんでしょうかね…。
そもそもカッコを使うべきだとおっしゃるのは、もっともだと私も思いますが、もち
ろんこれは考え方の個人差もあって、たとえばPerlあたりを長年やってた人などはけ
っこう省略する人が多いですし、「+−より×÷が先」ぐらいの当たり前としてわざ
わざ付けない人もいますし、人それぞれですね。私の場合は「ちゃちゃっと書く」感
覚で省略していた感じです。

確かなことは、付けない人は&&が優先されると信じている(いた)、ということです。
私もです…^^;

いずれにしましても、今後は気をつければ良いだけですから(過去のマクロは暇を見
て調べるとして)、私個人にとっては解決とも言えます。
いつもながらご丁寧なご対応ありがとうございました。


[ ]
RE:31597 論理否定の優先順位No.31697
IKKI さん 12/10/22 23:07
 
こんにちは。IKKI です。

今回追加されたヘルプページにちょっぴり間違いがあるようです。

誤『これらの問題を回避するためには、「! xxx」のような式の部分を必ず「!(xx
X)」のようにカッコで囲ってやる必要があります。』

正『これらの問題を回避するためには、「! xxx」のような式の部分を必ず「(!xx
X)」のようにカッコで囲ってやる必要があります。』

以上、ご報告まで。

[ ]
RE:31697 論理否定の優先順位No.31699
秀まるお2 さん 12/10/23 08:42
 
 毎度バグ情報ありがとうございます。まったくもって間違った説明をしてしま
ってました。しかも「xxx」が「xxX」になってるし。大変失礼しました。

 さっそく修正させていただきます。

[ ]