Boolean controler

Ako ste se ikada našli da ste pisali nekakvu funkciju tipa:

function myBoolean(string){
    if(string=='false')return false;
    ...
}

…ili…

function objectAsBoolean(x){
   return objectLength(x) > 0;
}

…vjerujem da ste otišli krivim putem. Znam, jer sam i ja mnogo puta…i nikako mi nije bilo jasno kako tom putu nikada nema kraja.

A nema kraja zato jer se tu postavljaju mnoga pitanja. Krenimo redom:

  • Hoćemo li integere 1/0 tretirati kao boolean stanja
  • Hoćemo li bilo koji integer tretirati kao boolean stanje
  • Hoćemo li numeričke vrijednosti stringa “1/0” tretirati kao boolean stanja true/false
  • Hoćemo li string “true”/“false” tretirati kao boolean stanja
  • Hoćemo li prazan string tretirati kao false
  • Hoćemo li string “null” tretirati kao false
  • Hoćemo li string “undefined” tretirati kao false
  • Hoćemo li uopće bilo koji string tretirati kao boolean stanje
  • Hoćemo li objekte (array/asocc) tretirati kao pozitvno boolean stanje
  • Hoćemo li prazne objekte tretirati onda kao false stanje
  • Kako ćemo reagirati ako nam u provjeru uleti element za kojega ni sami nismo sigurni kako bi ga tretirali. Bacat grešku ili jednostavno vratiti false.

To gore je 11 pitanja koji se daju odgovoriti sa DA ili NE, što će reći da imamo 11 digitalnih stanja.
A da bi predstavili sve kombinacije za 11 digitalnih stanja, to je 2048 kombinacija.

Stoga, ako ste krenuli pisati custom funkcije za određene provjere…da bi pokrili sve kombinacije…trebalo bi vam podosta funkcija. :slight_smile:
Naravno, parametriziranjem funkcija se smanjuje potreba pisanja različitih funkcija i naravno da želimo imati jednu jedinstvenu funkciju za kontroliranu provjeru Boolean stanja.

Postavlja se pitanje, kako parametrizirati takvu funkciju?

Meni se nekako u praksi pokazalo da je ovakva stanja najelegantnije parametrizirati sa jednim “stringom”, koji zavisno od toga da li sadržava neki karakter ili ne sadržava…utječe na ulazna digitalna stanja.

Npr. zamislimo funkciju element.getWidth()

…od te funkcije možemo željeti da nam vrati:

  • unutarnju širinu
  • širinu paddinga
  • širinu bordera
  • širinu margina
  • ili širinu svega toga zajedno
  • a možda baš trbamo samo unutarnju širinu + širinu paddinga.
    …vidimo da nam tako kombinacije ulaznih digitalnih stanja opet enormno rastu i nije ih lako sve pokriti. Ili ipak je?

Zamislimo parametar: “ipbm”.
Gdje svaki nosi jedno digitalno stanje, redom za:

  • i inner
  • p padding
  • b border
  • m margine

I sada uvijek možemo pozvati samo onoga tko nam treba, npr: element.getWidth("ip");

Sličnim pristupom mislim da je najelegantnije rješiti stanja za kontrolu tretiranja booleana. Samo mi je malo pofalilo slova, ali što je tu je:

  • 1 1/0 as true/false
  • d digits, string “1/0” as true/false
  • b booleans, string “true”/“false” as true/false
  • u string “undefined” as false
  • n string “null” as false
  • N real null as false
  • U real undefined as false
  • s any string as true, except declared false strings
  • D real digits as true except declared false digits
  • e empty object as false
  • z zero string length as false
  • o any object as true except declared false objects
  • t throw error on uncontroled type

Sada se funkcija poziva jako eleganto:

var state = myBoolean(x, "1dbunNUsDezot");

Zaebavam, ovo gore nije elegantno xd xd…ali je poprilično fleksibilno!
A ta fleksibilnost se može konfigurirati negdje u globalnom configu koji će reći funkciji myBoolean kako će se ponašati.

No što smo s time postigli? Pa i ne baš puno…u “normalnom režimu” rada nam je najčešće sasvim dovoljno i ono kako jezik nativno tretira boolean stanja. Pa nema neke potrebe tome doskakati za svaku situaciju. Ali je super biti fleksibilan u onim momentima kada nam ta fleksibilnost zatreba.

A kako na ulazu imamo 2048 stanja, teško da možemo u config fileu pogoditi koja solucija će nam zatrebati…kada ona uvijek može specifična od slučaja do slučaja.

Stoga, ako bi recimo u nekakvoj boolean kontroli htjeli tretirati prazan string kao true stanje …onda bi elegantija sintaksa bila:

var state = myBoolean(x, "-z");

gdje smo iz defaultnog control parametra “1dbunNUsDezot” isključili stanje z koje kaže da tretiramo prazan string as false. Sada ima smisla da se defaultno stanje postavi negdje u konfiguraciji, a onda po specifičnoj situacij možemo:

var state = myBoolean(x, "-z");       //skratiti defaultno stanje
var state = myBoolean(x, "+t");       //extendati defaultno stanje
var state = myBoolean(x, "1beot");    //prepisati defaultno stanje

var state = myBoolean(x, 1044); //numerirano ulazno digitalno stanje

kako imamo ograničen broj ulaznih digitalnih stanja, možemo svako predstaviti i brojem. Istina, ima jako puno brojeva, ali vjerujem da onih zanimljivh za upotrebu bi se isfiltriralo možda svega 15-ak. A 15 brojeva je pamtljivo i definitivno jedna od opcija za definirati ulazno stanje.

I čemu sve to? Zar nije moguće u toj nekoj specifičnoj situaciji upregnuti malo sirove if / else provjere i tako hendlati specifičnu situaciju?

Pa lokalno unutar projekta to nije problem tako napraviti, ali što ako npr. praviš helper komponentu/metodu koja unutar sebe nešto filtrira provjeravajući boolean stanja, gdje tretiranje booloean stanja zavisi od specifične situacije gdje će se ta komponenta upogoniti?

Kako će developer te komponente definirati da radi točno po želji onoga koji će je koristiti, ako ne ostaviš mogućnost taj koji ju koristi, da joj može eksplicitno definirati kako će se ponašati za određenu situaciju.
Gdje se ona naravno defaultno može ponašati nativno po jeziku, ukoliko ne dobije specifičnu naredbu kako će tretirati boolean stanja.

Kako se dosad još nisam sreo da se netko pozabavio ovom problematikom, moj doprinos je:

1dbunNUsDezot

:smiley:

Huh :dizzy_face::dizzy_face:

Daj nemoj me zajebavati da je tebi ovo fleksibilno po bilo cemu.Ovo samo dize kompleksnost koda radi 0 benefita.

I uz to moras stalno gledati u neki cheatsheet kako bi shvatio sta ovaj niz karaktera znaci.

Mozes li malo koda dati za ovaj primjer, posto mi nije bas jasno na sta mislis konkretno.

Pa fleksibilnost i kompleksnost najčešće uvijek dolaze u takvom paru.
Ako podižeš nečemu stupanj fleksibilnsoti, najčešće se podiže i stupanj kompleksnosti.

Gornji primjer pokazuje kako se fleksibilno može upravljati načinom tretiranjem booleana, naravno da se uz to onda podiže i stupanj kompleksnosti.

Ja sam tražio način da što jednostavnije mogu uključiti tu fleksibilnost …tako da se upravo stupanj kompleksnosti što manje podigne sa dodanom fleksibilnošću.

Ti ako imaš jednostavniji način da dodaš istu fleksibilnost, slobodno daj ideju. Rado ću je prihvatiti ako bude OK, jer ne tvrdim da je moje rješenje top. Već duže vrijeme mi skreću misli kako doskočiti ovom problemu…ali ne kažem da sam ponudio extra rješenje.

Ali da kažeš da ovo ne podiže stupanj fleksibilnosti, to je apsolutno krivo. Naravno da podiže.

S time da ako je i dobit fleksibilnosti svega mizerna…opet ne postoji nikakav problem. Jer gornji pristup nije zamjena postojećeg, nego samo opcionalni dodatak na postojeće.

A opet je nužnost za one funkcije koje žele omogućiti da onaj tko ih koristi da ima tu fleksibilnost u tretiranju booleana. Takvih funkcija nema nešto naročito puno, ali ih ima.

Evo ti hint: U JSu možeš pisati var x = y || z || c;

Te će x biti prva varijabla iz skupa (y,z,c) koja ispunjava true state.
Ali nad takvim izborom nemaš nikakvu kontrolu po čemu će se tretirati koja varijabla ispunjava true state.
Nadalje, u nekim jezicima niti nemaš mogućnost pisanja takvog code-a…pa se takvo ponašanje može opisati zasebnom metodom, koju ja osobno zovem: var x = chuse(y,z,c);

A nimalo neškodi imati opciju modelirati ponašanje metode chuse(), kada nam je recimo prazan string dobar kandidat da bude odabran…a samo null-ovi su recimo ono što ne želimo.

Kao što rekoh, svaka situacija može imati 2048 satanja kako bi možda željeli da se u dotičnom momentu ponaša metoda chuse.

No to nije samo kod metode chuse. Npr. funkcije koje extendaju objekt isto mogu razmišljati što će preskočiti… itd. itd.
Imaš dosta funkcija čije ponašanje možeš bitno modelirati samo ako im kažeš što će im predstavljati true, a što false stanje.

Zasto bih i trebao imati kontrolu nad tim, ne razumijem ?

Ako JS kaze da je prazan string falsy vrijednost, zasto bi ga ti tretirao kao truthy vrijednost ? Na taj nacin mozes jedino zbuniti osobu koja dolazi raditi poslije tebe ili s tobom na projekat.

Mozda masim srz, tako da bih volio dobiti neki opipljiv odgovor/primjer na ovo :slight_smile:

Zato jer si onda ograničen sa onime što možeš raditi sa ovom poprilično elegantnom sintaksom:

var x = y || z || c;

Prazan string može biti nekada ono što tražiš…isto kao što i 0 (nula) može biti ponekada ono što očekuješ na ulazu.
Kada imaš takva očekivanja na ulazu gdje ti stižu parametri, više ne možeš koristiti gore spomenutu elegantnu sintaksu. …nego ti se code pretvara u nešto tipa:

var speed ? userSpeed !== undefined ? usedSpeed : defaultSpeed;

što je dosta ružnije od:

var speed = userSpeed || defaultSpeed;

I to je već tako ako u “bazenu” biramo između dvije brzine. Ako se skup bazena poveća, npr. da imamo više mogućih inputBrzina od usera, gdje niti jedna ne mora biti zadana…onda se code drastično poružnuje i moramo već pribjegavati kojekakvim metodama.

A kako ja uvijek metode pišem na način da se kasnije mogu reciklirati…onda tragam za univerzalnim rješenjima takvih problema. U ovom slučaju mi je to:

var speed = chuse([userSpeed1, userSpeed2, userSpeed3, defaultSpeed], "-1D");

Gdje je “-1D” flag instrukcija kako će se brojevi tretirati kod provjere na true/false.
Na samoj sintaksi tih flag karaketra ću još poraditi…shvatio sam svašta nešto pišući ovu temu. :slight_smile:

I još jedna stvar za isto ovo pitanje.
Tako kaže JS, PHP kaže drugačije, C# drugačije…itd.
Ako želiš imati pouzdan rad metoda unutar različitih “jezičnih” okruženja, onda je svakako dobro imati centraliziranu kontrolu …ili ti ga postaviti vlastite kontrolere nad bitnim aspektima programa.

Svaki jezik je tu prvenstveno da može stroju opisati naš tok misli + spojiti te radnje sa različitim periferijama računala.
Tako svaki program ima vlastitu periferiju…JS te spaja sa browserom, PHP sa bazom… neki drugi programski jezik te spaja sa POS printerom… i to je ono što ih nužno razlikuje.
No ono što im svima može biti zajedničko, da mogu opisati naš tok misli.

I svaki jezik tu unosi nešto svoje da bi tu ulogu bolje odradio. No jezik koji može objediniti sve aspekte pojedinih programa je onda cjeloukupniji jezik.
Ja tako nastojim sa svojim librirayem izjednačavati nebitne razlike između različitih jezika …tako što iste metode normaliziram na ista imena i na iste setove input parametara …dok istovremeno nastojim objediniti one razlike koje su individualne prednosti svakog od tih jezika. Tako dobiješ alat koji je objedinio prednosti dva različita alata.

U tom smislu, meni je velika prepreka da jedan jezik razmišlja na svoj način kod tretiranja booleana, a drugi na svoj. A ja da nemam na tim kontrolu kada želim imati.

Ili jednostavno ovako

var speed = userSpeed1 || userSpeed2 || userSpeed3 || defaultSpeed

Kakvim metodama mora se pribjegavati ? undefined/null je falsy vrijednost tako da ako ne zadas nista vratit ce ti defaultnu vrijednost :smiley:

Fakat ne kontam o cemu pricas.

Naravno to je odlicno :smiley: Ja poznajem JS i kako type casting radi i dodjem raditi s tobom u okruzenje gdje je sve drugacije - bi se i slagali nema sta :smiley:

A što ako user definira da je brzina objekta jednaka nula? :slight_smile:

A o tome ti pricas :smiley:

To je kako jezik sam radi, tako da bih malo refaktorirao funkciju da odgovara mojim potrebama.Ocito je da ovo var speed = userSpeed1 || userSpeed2 || userSpeed3 || defaultSpeed nije rijesenje za use-case koji ti imas, tako da ne treba nista "forsirati’.

I dalje stojim iza toga da cu se uvijek oslanjati na jezik i njegova pravila nego na nesto poput ovog

var state = myBoolean(x, "1dbunNUsDezot")

Razlog sam vec naveo :slight_smile:

1 Like

Pa ne trebam ti ja o tome pričat, code koji si napisao

je sasvim dovoljan da uočiš koji je tu edge-case.
Pogotovo što sam ti još ranije napisao:

…i onda ti nakon svega ne uočiš da je sasvim legitimno da brzina bude zadana kao nula.
I onda sam ti ja nakon godinu dana kriv što ne znam objašnjavati. :stuck_out_tongue: :stuck_out_tongue:

A sada dalje…što me još nisi shvatio…

Nećeš nikada morati pisati tako. :slight_smile:
Jer u 99.99% slučajeva ćeš trebati samo iz defaultnog flag izraza isključiti uljeza, tako će se gornji selektor brzina pisati na način:

Flag je znači samo: "-1", te nije nikakva kobasica.
minus (-) je instrukcija da iz defautlnog flaga isključuješ karaktere, a “1” je instrukcija da se 1 tretira kao true, a 0 kao false. Pa pošto zbog minusa to pravilo isključimo iz boolean provjere…0 će nam biti tretirana kao true i stvar će raditi po očekivanom.
Ako je to kompleksan pristup za pokriti 2048 različitih kombinacija, ubij me. :smiley:
Jedino velim, na sintaksi flaga ću još poraditi…imam tu zanimljivih ideja.

Ako možeš ponuditi elegantnije rješenje, rado prihvaćam.
Ponudi kako bi rješio gornji problem…ali generalno rješenje koje se može reciklirati.

I imaj na umu da chuse() nije jedina metoda koja se može oslanjati na boolean provjeru unutar sebe…gdje mi želimo izvana imati kontrolu nad tim kako će ona unutar sebe tretirati boolean stanja za različite tipove varijabli.

I još ovo da iskomentiram…

Proširenje nije ograničenje. Ne kužim kako to uporno ignoriraš shvatiti.
Ako se nešto uvede dodatno…ti nisi prisiljen to koristiti…i nisi ograničen koristiti nativni pristup koji ti je i dalje dostupan.

Ali ako naletiš na situaciju kao iz primjera sa odabirom prve definirane brzine … onda je na tebi hoćeš li koristiti tu dodanu mogućnost da to riješiš elegantno…ili ćeš pisati svaki puta špageti-code da izvučeš takvu situaciju.

Nije to nikakav edge-case vec problem koji ti ti zadao nije uopste use-case za ovakav dijelic koda:

U “normalnim” jezicima, kao sto si i sam spomenuo, to nije ni dozovoljeno.A posto u JS-u mozes raditi prakticno sta te volja, onda dobijes takav rezultat kakav jeste.

Da to je sasvim legitmno, ali ne bas legitimno za var x = y || z || c na koji si me naveo, ali ajde reci cemo da mi je promaklo :slight_smile:

Imamo razlicite definicije elegancije tako da bolje ne :slight_smile:

Ko je rekao da je ogranicenje ? Postoji nesto sto se zove stil kodiranja, koji svaki projekat/tim/firma ima.Vjerujem da bi super konzistentan kod izasao kad bi ti koristio te tvoje funkcije, a ja nesto totalno drugo da rijesim isti problem.

Izgleda da imamo razlicite definicije spageti koda takodjer :joy:

Umalo da zaboravim ovo :smiley:
Nakon godinu dana i toliko ispisanih tema o Normu, koliko je osoba shvatilo o cemu se radi ? Mozda bolje pitanje, koliko je osoba shvatilo odmah ? :smiley:

Gornji problem je trivijalan…rješenje kakvo god se nakuca u 2 minute. Volio bi stvarno vidjeti što tebi znači elegantni pristup takvim sitnicama.

Nego, rekao sam da me nečemu ova tema naučila …
…osvjestila me je da da može postojati globalna kontrola kako će se ti flagovi digitalnih stanja tretirati.
To je zaslužilo zasebnu temu: Flags as string

@belmin , toliko buke, a teško ti je pokazati taj lijepi code?

Možda ja sada masim srz, ali mislim da je u redu da onaj koji govori da jedan pristup ne valja, da pokaže koja solucija bi onda bila valjana?

Ti meni kazes da mi je tesko pokazati kod ? haha :smiley:

Pokazacu, al daj mi malo vremena da skontam nesto kripticno u tvom stilu :wink:

Kao sto rekoh treba mi vise konteksta malo, definisi neke zahtjeve pa cu ti vrlo rado kodom pokazati kako se to radi - bar za mene nikad to nije bio problem :wink:

1 Like

Ok, specka.

  • razmisli zašto je tvoje ponuđeno rješenje za deklaraciju brzine nedovoljno precizno napisano. (Hint: brzina može biti nula)

  • rješiti isti problem tako da složiš metodu koja će se moći lako reciklirati na drugim projektima za slične situacije

  • plus bodovi. Ako osmisliš metodu tako da je možemo lako podijeliti i sa ovim drugim odjelom softweraša koji ne tipkaju u JS-u

  1. 0 u boolean ekspresiji se castuje u false vrijednost, tako JS radi.
  2. vjerovatno necu “reciklirati” ili cu reciklirati u manjem scope-u (ukoliko je potrebno)
  3. Ne pada mi na pamet, jer kao sto rekoh oslanjam se na jezik i na prakse koje su vezane za taj jezik.

Za sada nista od koda, zao mi je :slight_smile:

A lagan zadatak…što bi bilo tek da vidiš koliko su kompleksni zadaci kada radiš kompajliranje nekog codea :slight_smile:

Zadnja verzija Typescripta je uvela Nullish Coalescing operator, a isti dolazi uskoro i u JS

function getSpeed(speed: number) {
  const defaultSpeed = 60;

  return speed ?? defaultSpeed;
}

console.log(getSpeed(0))

Nadam se da je ova solucija dovoljno kratka i genericna, tj. da se lako “reciklira” :smiley:

P.S Ko koristi Babel moze odmah koristiti ovu opciju

Evo jedan fantastičan twitter nalog a koji je u skladu s temom:

https://twitter.com/everyboolean

2 Likeova

Za mene ništa novo da stvari o kojima pričam tek dolaze u praksi.
U zadnjih 10g. se nije desilo da sam nešto izmislio što nije naknadno došlo…ili da je već postojalo. Možda svega par stvari tek čeka da bude globalno “izmišljeno” i prihvaćeno.

Pošto si ti imao poprilično tvrdoglav stav u smjeru da ovakvo nešto nema svoju primjenu i smisao…nadam se da sada uviđaš da govorim o stvarima koje prije ili kasnije zajednica shvati da trebaju postojati. Šteta jedino što ti treba potvrda od zajednice da nešto treba postojati…a da ne možeš tu istu potvrdu pronaći u samoj funkcionalnosti/potrebi neke ideje.

Jer svaka ideja govori sama za sebe da je korisna…nije potreban nitko da ju “aprova” da bi ideja dobila svoju svrhu i smisao. :wink:

1 Like

Eto ti lajk, dao bih i 2 al ne moze.

Ako stvarno smatras da je ovo tvoje rijesenje u rangu nullish coalescing operatora, onda fakat ne znam :sweat_smile:

Nisam ja tvrdoglav, vec ne trazim genericno rijesenje za sve zivo i radije cu se fokusirati na konkretnu implementaciju i uraditi dodatni check nego imati nesto ovako

var state = myBoolean(x, "1beot");

Ne zelim se vise ponavljati zasto tako ne bih rijesavao stvari, mislim da sam rekao vec dosta puta.
Medjutim kad je vec tu nesto u samom jeziku, koje rijesava taj specifican problem na jednostavan, citljiv i elegantan nacin zasto to ne bih koristio ?