stuncloud/UWSCR

サポート外の使い方ですが、関数Splitを通した後の「False」 の両面性について。

Closed this issue · 17 comments

質問

False を関数Splitの引数に含めた場合、その戻り値のFalseは使われ方によってはTrueの働きをし、
True/Falseの両面性を持つように成ります。一方、Trueの場合はSplit後も正常な働きをします。

後になって、TrueやFalseは文字列ではない為、仕様外の使い方だと気付きましたが、一応知らせておきます。

ちなみにUWSCのSplitでは、エラーとしては検知されませんが、その戻り値を使おうとした時に
Could not convert variant of type (UnicodeString) into type (Double)
というエラーになります。

補足用コード

再現方法
a = True; b = False
c = a + "," + b
aa = SPLIT( c , ",")

If aa[0] Then                      //UWSCは ここでエラー :  Could not convert ・・・
  Print aa[0]              // True
EndIf
If aa[1] Then        //  <==  aa[1](False)はTrueとして扱われ、下のPrintに行ってしまう!  
   Print aa[1]             //  False   <== Print関数ではFalseの扱い
EndIf 
If aa[0] = True Then      
  Print aa[0]              //  True
EndIf
If aa[1] = False Then     //  <==  ここでは、aa[1]はFalseとして扱われている。
   Print aa[1]             //  False 
EndIf
If aa[0] = False Then      
  Print aa[0]              // 
EndIf
If aa[1] = True Then      //  <==  ここでも、aa[1]は正しくFalseとして扱われている。
   Print aa[1]             // 
EndIf

バージョン

1.0.0

実行環境

Windows 10

@DIYJii
c"True,False"という文字列になるのでaa["True", "False"]という文字列の配列になります
文字列と真偽値リテラルの比較は真偽値を文字列として扱っているため

  • "True" == TRUE
  • "False" == FALSE

はいずれも真です

今回は勘違いから文字列であるのに真偽値として振る舞うことを期待されての質問だと見受けられました
値の型についてはtype_of関数を使って確認できます
このようなケースでは値の型を確認していただくと動作の理由への理解にもつながるかと思います

回答は以上です
解決されましたらこのissueはクローズしていただいて構いません

以下は余談です
文字列は条件式においてはtruthyであるため以下はいずれも「真」を出力します

print "True" ? "真" : "偽"
print "False" ? "真" : "偽"

真偽値のような文字列を真偽値として扱うことは仕様上ありません
もしそのような文字列を真偽値として扱いたい場合はeval関数を利用してください

print eval("True") ? "真" : "偽" //
print eval("False") ? "真" : "偽" //

@DIYJii 条件式に文字列を入れる例が提示されたスクリプト内にありましたね、見落としてました
余談のとこ余談じゃなかったです、失礼しました

cは文字列になるとは、説明してもらう迄思ってもいませんでした。それで、新たに次の事をやって見ました。

If "hoge" Then
Print "hoge"
Else
Print "fugo"
EndIf

これが、何と 「hoge」 とPrint するんですよ!?

UWSCでは勿論 「If "hoge" Then」 はSyntaxErrorで引っ掛かります。

False がおかしいのではなく、If関数が文字列をエラーなしに受け入れて、さらにそれら全てをTrue扱いしているという2つの問題が潜在しているように見えますが?

@DIYJii 仕様です

真偽判定の説明にある通りです、if等の条件式は標準では真偽値を要求するわけではなく、式の真偽性を評価しています
真偽性において文字列は真(truthy)です
(このような動作はJavaScript等で見られます)
また、UWSCRではあらゆる値の真偽性を評価するためエラーになることはありません

これを避けるにはOPTION FORCEBOOLを指定してください
このオプションを指定することで条件式は真偽値以外をエラーとするようになります

文字列がエラーとなるUWSCでも例えば以下が有効です

if NULL then
    print "出力される"
endif

一見不可解ですがNULLは真と判定されています
また検証はしていませんがUWSCでも文字列によっては条件式として受け付けられる可能性があります、例えば"1"などはdoubleに変換できる可能性があるからです

UWSCRの条件式仕様は

  • JavaScript等と同じように値の真偽性を評価することを標準とする
  • OPTION FORCEBOOLを付加することによりRustのように真偽値のみを有効とする

ことで柔軟なコーディングを実現しています

やはり数値変換可能な文字列であればUWSCでも有効ですね

// UWSC
// 真 が出力される
if "1" then
    print "真"
else
    print "偽"
endif

判りました。UWSCと変わらずに走らせるには OPTION FORCEBOOL ですね。
他にも, UWSCと同じ仕様にする設定は有りますか?
UWSC 育ちの私には、文字列はTrue扱い云々というのはチンプンカンプンの話です。
それから、マニュアルにある下の説明では、UWSCと全く変わらずに使えるとしか思えませんでした。

単行if
if 式 then 文 [else 文]
if foo then bar // foo が真の場合 bar が実行され、偽の場合なにもしない
if foo then bar else baz// foo が真の場合 bar、偽の場合 baz が実行される

私だけが、わざわざこうやって長時間掛けて講義をして貰っても、他の人には通じない訳ですから、真や偽に*を付ける等して
UWSCから仕様を拡張したので、どこそこを読んで、真偽判定やOption設定を熟読するように等の注釈をマニュアルに入れるようお願いします。

別に、実害が有ったわけでも無く、将来起きるかも知れない混乱を危惧しただけの事ですので、この件はこれで終わりにしたいと思います。また、移行作業に集中します。長時間有難うございました。もし、何もなければそちらでClose願います。

UWSCと変わらずに走らせるには OPTION FORCEBOOL ですね。

いえ、UWSCは条件式が返す値をVARIANT型変換によりVT_R8 (vartypeでいうVAR_DOUBLE) に変換し、0であれば偽、それ以外は真としているようです
FORCEBOOLは条件式で真偽値、すなわちTRUEまたはFALSEを返す式しか受け付けなくするためのものであり、これはUWSCよりも判定が厳しくなります
このオプションがない場合のほうが (一部の式をエラーとしなくなるという差はあれど) UWSCに近い動きになります
(VARIANT変換による判定を完全に再現できるわけではありません)

条件式を伴う式または文の解説に真偽判定へのリンクを貼るなど、ドキュメントの改善は行うつもりです

  • if文
  • 三項演算子
  • while-wend
  • repeat-until

UWSCと同じ仕様にする設定は有りますか?

そもそもそういうものがありません
違う部分は違うし、合わせられる部分は合わせているだけで、それを設定でどうにかする仕組みはありません

ForceBool にすると If a Then は受けつけなく If a = b Then しか使えなくなるという理解で良いですか?
もう、遅いので返事は明日、お願いします。

ForceBool にすると If a Then は受けつけなく If a = b Then しか使えなくなるという理解で良いですか?

前者は場合によります
以下に例を示します

OPTION FORCEBOOL
dim a = TRUE // 真偽値
if a then // 有効
endif

dim b = 1 // 真偽値以外
if b then // エラー
endif

ifthen の間の式がTRUEまたはFALSEを返すことを期待するのがFORCEBOOLです

該当する式の具体例は

  1. 真偽値リテラル (TRUE, FALSE の直接記述)
  2. 比較式 (=, ==, <>, !=, <, <=, >, >= を用いた右辺と左辺の比較)
  3. 真偽値である変数や定数
  4. 真偽値を返す関数
  5. 論理演算 (AND, OR を用いた右辺と左辺の比較)
  6. 右辺が真偽値である代入式

などがあります
以下はコード例となります (いずれも有効です)

OPTION FORCEBOOL

// 1.
if TRUE then
endif
if FALSE then
endif

// 2.
if 1 = 2 then
endif
if 1 < 2 then
endif

// 3. 
dim a = FALSE
const b = TRUE

if a then
endif
if b then
endif

// 4. 
function f()
    result = TRUE
fend

if f() then
endif

// 5.
if TRUE or FALSE then
endif

// 6.
if c := TRUE then // cに代入されたTRUEが返る
endif

これが全てではありませんが、記述された条件式の評価結果がTRUEまたはFALSEであれば良いということがご理解いただけるでしょうか

丁寧に例を挙げて頂き、ありがとうございました。
私は、例に挙げられた範囲内の使い方しかしませんので、FORCEBOOLで解決です。
お陰様で、If "hoge" Then Print "hoge" は、エラーで引っかかるようになりました。
UWSCからの移行等の場合、慣れるまではFORCEBOOLをセットするのがお勧めだと思います。

なお、

OPTION FORCEBOOL = True とすると、Printウィンドウに
OPTION FORCEBOOL = False とすると、コンソールに
「hoge」 とプリントが出ます。

1番目はTrueなのに FORCEBOOLが外れてしまうのと、両者のPrint画面が異なるのが少し気になるのですが、
仕様書通りなのでしょうか?
それから、Script内にOPTIONを全く書かないと、Printウィンドウは開かず、Printはコンソールのみに出力されます。

アプリ側画面との住み分け等の関係で、Printの画面について、少しやり取りしたいのですが、その内またお願いします。

UWSCからの移行等の場合、慣れるまではFORCEBOOLをセットするのがお勧めだと思います。

ちょいちょいこういう書き方をされますが何視点なんですかね?
UWSCからの移行であれば互換性を考えればFORCEBOOLはむしろない方が良いです、なのでオプションとしています

OPTION FORCEBOOL = True とすると、Printウィンドウに
OPTION FORCEBOOL = False とすると、コンソールに
「hoge」 とプリントが出ます。

Printウィンドウへの出力制御にはOPTION GUIPRINTがあるのですが、そうではなくFORCEBOOLでprintの出力先が変わっているということですか?
あとで確認してみます

@DIYJii バグでした #167

FORCEBOOLを有効にする場合はOPTION FORCEBOOLとだけ記述するようにしてください
または、設定ファイルのoptions.force_booltrueにします

{
  "options": {
    "force_bool": true
  }
}

「ちょいちょいこういう書き方をされますが何視点なんですかね?」

私は、自分の経験から、下の様な訳の分からん事に成る事を避けるよう 保険の意味で「OPTION FORCEBOOL = True」 をセットするよう、他のユーザーにもお勧めする訳です。

OPTION FORCEBOOL = False // Default
If "False" Then Print "<#DBL>False<#DBL> = True" //"False" = True
If "False" = False Then Print "<#DBL>False<#DBL> = False" //"False" = False

普通の人間の感覚からしたら、「何これ?嘘でしょー!」ってなりませんか?
ちなみに、Javaでもこうなるのですか?

元はと言えば、私のコーディング・エラーが原因ではありますが、今迄はテスト・ランでエラーとして引っ掛っていた物が、UWSCRでは、何もエラーに引っかからず、ただアプリが異常な動きをするようになり、どこに問題が有るのかを見つけるのに、非常に時間が掛りました。これこそ、あなたのよく言う、「コストが掛る」というやつです。それも、あなたの言うような創造的作業に掛るコストでは無く、無い方が良いに決まっている、非生産的なコストです。ユーザーは1人ではないですから、放置すれば将来、何人ものユーザーのコストが掛る事になり兼ねません。
それに、エラー検知されずに予想外の結果が起きるので,ファイルを扱うアプリでは、データ破壊や、ファイル消滅につながる恐れもあり、非常に危険です。因みに、私のアプリでは、キーワード検索の精度を上げるため、2年近くかけて構築して来たファイルも有ります。他にも、毎日アップデートを掛けているファイルが約30。今回のバージョンで、解決はされたたものの、#157の問題が絡んで、上の問題解析中にプロセスを中断する事が何度も有り、その度にファイルが真っ白になって、ヒヤヒヤしました。常に、バックアップは取るようにしていますから、今のところ無事ではありますが。

そんな訳で、今迄蓄積したアセットを大事にしながら、前に進む為には、急激な変化を起こすと不測の事故に繋がるので、少しずつ安全を確認しながら変更を加えてゆく必要性があるのと、まだこれから来るであろうUWSCのUser達が同じ苦労をしないで済むようにと思って、色々と発言をしている訳です。
あなたとしては、新しく組み込んだ機能を早く使って貰いたい処を、バグの話や、後ろ向きな話ばかり持ち込まれて、色々と気分の悪い事が多い時期だとは思います。でも、私も新しい機能を搭載したUWSCRを使って、より良いアプリにしたい一心で、日々、色々な困難をいとわず、バグ・レポートや提案で少しは協力しているつもりですから、そう、あんまり、カリカリしないで下さい。 なお、私はJavaの知識があまり無いところを、色々時間を掛けて丁寧に説明してもらっている事、大変感謝しています。

UWSCではifの条件に数値を用いるという使われ方が少なからずあるんですよ

//
if pos(a, b) then
  print "found " + a
endif

FORCEBOOLはそれもエラーにするのでUWSCからの移行にはおすすめできません
また、そもそもUWSCで文字列をifの条件にいれる人はいません (エラーになるのだからそんなコード書かない)
なので問題は起きないはずなんですけどね

FORCEBOOLをお勧めしますと書かれても、僕しか読んでないのでそれを僕に勧められても???という話なんですけどね
あなたは想像の中の他ユーザーを盾にあれこれ言われてますが、理由を突き詰めるとそれはあなた個人の希望であり、とてもひとりよがりな印象です

僕としてはですね、既存のスクリプトを無理にUWSCRに移行する必要はないと思うんですよね
それらはUWSCでも動くわけですから
僕もそのようなケースでUWSCを使ってますしね

なにか新しいスクリプトを書く際に機能の拡張されているUWSCRを使うほうが筋が良いですよね、その際にはUWSCの知識も役に立つわけです

もともと100%の互換性は捨てていて、例えばgetitemなどがその最たるものですが、UWSCの不便な点を切り捨てることで将来の利便性を取ったわけです
その中でここが違うのが困るな、ということがあってもそれはUWSCRの流儀に合わせてもらうしかないですね

ちなみに、Javaでもこうなるのですか?

JavaScriptです
コンソールですぐに試せますよ

let a = "hoge" ? "真" : "偽";
console.log(a); // 真

あとは身近なところではPowerShellもそうです、こちらもすぐ試せますよ

条件式で真偽の値ではなく真偽性を判定することは珍しいことではありません
その是非についてはまた別の問題ですけれど、少なくともUWSCRでは是としています

もう、ここは止めて、#168に行きましょう

#168のやり取りで、if a then でなく If eval(a) then とすれば "false" = true は解決すると判明。

Closeします。