Přejít k navigační liště

Zdroják » Různé » CoffeeScript: nový jazyk, nové chytáky

CoffeeScript: nový jazyk, nové chytáky

Články Různé

CoffeeScript vzbudil mezi vývojáři webových aplikací slušný zájem, mnozí si pochvalují jeho vyjadřovací schopnosti a eleganci. Přesto má CoffeeScript, jako každý jazyk, kromě příjemných překvapení i některé záludnosti a tajemná zákoutí, do nichž může nepřipravený vývojář snadno padnout.

CoffeeScript je velmi mladý jazyk. Vývojářům ještě nenabízí vyspělý ekosystém (například debuggery), ani s literaturou to není tak úplně slavné a vědění se šíří zatím převážně v diskusních fórech a na Twitteru. První skutečná kniha, která vyšla na téma CoffeeScript, byla vydána nakladatelstvím Pragmatic Programmers, jmenuje se CoffeeScript: Accelerated JavaScript Development a autorem je Trevor Burnham.

V této knize naleznete nejen informace o programování v CoffeeScriptu či praktické rady (jak instalovat, jak debuggovat, kde nalézt vhodné pluginy pro editory), ale i upozornění na některá úskalí, která CoffeeScript (potažmo JavaScript) přináší, stejně jako tipy a triky, které vám používání CoffeeScriptu zpříjemní. V dalším textu se na některá taková tajemství, probíraná ve zmíněné knize, podíváme.

Když na mezeře záleží…

Z většiny programovacích jazyků jsme zvyklí, že na nějaké té mezeře většinou nezáleží. V JavaScriptu například není rozdíl mezi těmito dvěma zápisy:

var prefix = "#prvek_";
// zápis 1
var id1 = prefix + 12;
// zápis 2 - jedna mezera chybí
var id2 = prefix +12;

V CoffeeScriptu bude rozdíl významný:

prefix = "#prvek_"
id1 = prefix + 12 # == #prvek_12
id2 = prefix +12 # TypeError

Proč? Vzpomeňme na to, že Coffeescript umožňuje zapsat volání funkcí bez závorek. Poslední řádek tak bude přeložen jako

var id2 = prefix(+12);

což je něco jiného, než jsme zamýšleli.

Stejně tak může problémy způsobit fakt, že toto vyhodnocování operátorů je asociativní zprava, takže konstrukce

console.log (fn 3, fn 4)

vypíše pouze výsledek volání funkce fn(3). Kompiler totiž vyhodnotí zápis jako:

console.log (fn (3, fn (4)))

tedy zase opět něco zcela jiného.

Doporučení: parametry vnořených volání funkcí pište do závorek; vynechat je můžete pouze u volání nejvyšší úrovně. Tedy:  console.log fn(3), fn(4).

Pozor na mezeru mezi jménem funkce a závorkou: console.log fn (3), fn (4) bude vyhodnocena opět jinak – tím výše zmíněným způsobem, tedy jako vnořené volání funkce fn!

Scope – oblast viditelnosti

Záhadné chyby může způsobit implicitní pravidlo oboru platnosti proměnných. Proměnné se v Coffeescriptu nedefinují explicitně, ale využívají se tři pravidla:

  1. Funkce vytváří oblast viditelnosti (scope), a jediný způsob, jak vytvořit oblast viditelnosti, je definice funkce.
  2. Proměnná je viditelná v oblasti nejvyšší úrovně, kde jí byla přiřazena hodnota.
  3. Mimo scope není proměnná viditelná.

Jak ukazuje Trevor Burnham v kapitole 2.2, přináší to někdy podivuhodné konsekvence:

x = 42
init = -> x = 0
init()
console.log x

Výsledek bude nula, protože definice funkce na řádku 2 vyhodnotí x jako globální proměnnou (resp. existující v nadřazeném scope). Co způsobí prohození řádků 1 a 2?

init = -> x = 0
x = 42
init()
console.log x

Tentokrát bude výsledek 42, protože v okamžiku definice funkce (na řádku 1) bude x neznámé, a bude vyhodnoceno tedy jako lokální proměnná viditelná pouze ve funkci init.

Je to logické a vyplývá to z pravidel viditelnosti proměnných v CoffeeScriptu, přesto to dokáže zaskočit. A aby nebylo zmatků dost: pokud má funkce parametr, pojmenovaný stejně jako „globální“ proměnná (správně: jako proměnná v nadřazeném scope), bude v těle funkce rovněž lokální. Upravíme první příklad:

x = 42
triple = (x) -> x * 3
console.log triple x
console.log x

V těle funkce triple bude proměnná x tentokrát lokální!

== a ===

V JavaScriptu je zásadní rozdíl mezi operátory == a ===. Viz lehce upravený příklad z WTFJS:

var a = 0, b = '', c = '0';
a == b; // true
a == c; // true
b == c; // false

Matematik by řekl, že operátor == není tranzitivní. CoffeeScript v tomto ohledu lehce programátorovi pomůže: pokud zapíšete ==, přeloží ho jako ===. Jak v CoffeeScriptu ale zapíšete ekvivalent JS operátoru ==? Odpověď: Nijak. Vždy se porovnává typově.

key:value

Představme si definici objektu:

x = 10
y = 20
radius = 5
kruh = {x: x, y: y, radius: radius}

CoffeeScript má pro případy, kdy se vlastnost jmenuje stejně jako proměnná, která je přiřazována, zkratku. Poslední řádek lze tedy zapsat i takto:

kruh = {x, y, radius}

Ovšem CoffeeScript jde ještě o kousek dál. Vzpomínáte na „destrukturované přiřazení“?

pole = [10, 20]
[a, b] = pole

Stejným způsobem lze přiřadit i vlastnosti objektů:

{x: mojeX, y: mojeY} = kruh

A opět: pokud se vlastnost jmenuje stejně jako proměnná, do níž bude přiřazováno, lze zkrátit:

{x, y} = kruh

Autor uvádí i příklad při vývoji pro Node.js – píšete testy a potřebujete metody assert.ok a assert.strictEqual. Můžete použít konstrukci:

{ok, strictEqual} = require "assert"

a budete mít obě metody dostupné v proměnných ok a strictEqual.

Destrukturované přiřazení lze zapsat i vnořené – parsování dat v JSON je pak lahůdka:

{result: [code, text]} = serverResponse

Když super() není super

CoffeeScript usnadňuje i psaní tříd „běžným“ způsobem (a odstiňuje tak programátora od zapeklitostí prototypové dědičnosti). K volání metod předka pak používá obvyklé volání metody super().

class Vyrobek
  constructor: (zaruka) ->
    DBzaruk.save(this) if zaruka
     
class Toaster extends Vyrobek
  constructor: (zaruka) ->
    super()

V takovémhle případě je volání metody rodičovské třídy chybně – nepředáme parametr zaruka. Můžeme napsat super(zaruka), ale CoffeeScript má (opět) pohodlnější zkratku:

class Toaster extends Vyrobek
  constructor: (zaruka) ->
    super

Takto zapsáno zavolá stejnojmennou metodu rodičovské třídy se všemi parametry.

A dál…?

CoffeeScript představuje pro vývojáře novou neprobádanou oblast, kde je možné za každým rohem narazit na zajímavou možnost, která vám ulehčí práci – ovšem taky můžete narazit i v místech, kde si jste jistí, že přesně víte, co děláte. Doufejme, že tento článek alespoň trochu osvětlil některá potenciálně nebezpečná zákoutí a ušetřil vám krušné chvíle při ladění.

Komentáře

Subscribe
Upozornit na
guest
19 Komentářů
Nejstarší
Nejnovější Most Voted
Inline Feedbacks
View all comments
pepca

Už podle první kapitoly o závorkách pri volání funkcí je zřejmé, že ten jazyk stojí za prd.

Jiří Knesl

Stojí tak za prd, že mám díky němu mnohem čitelnější a o třetinu kratší zdrojáky.

Vždy, když máte v jazyku nějaké implicitní chování, je nutné vyjímku popsat explicitně. Pokud dokážete vymyslet lepší logiku vynechávání zbytečných závorek, zkuste ji sem, prosím, napsat.

Makovec

Čitelnější? Když se „foo + 1“ liší od „foo +1“ tak mně osobně to přijde méně čitelné. Chci programovat a ne si pamatovat esoterická pravidla o všech možnostech jak zapsat volání fuknce a kombinací možných záměn závorek a whitespace.

Jiří Knesl

O všech těchto esoterických chytácích se dozvídám až z tohoto článku (mimo to závorkování, což ale bohužel lépe udělat nejde – což vím, protože jsem si to zkoušel navrhnout jinou logikou a tam došlo k chybám zase v odlišných situacích). Už jsem v Coffee napsal desítky tříd, plno unit testů a to jak na client-side, tak na server-side a žádnou z chyb jsem ani omylem nepotkal.

Existují 2 časté workflow: foo+bar a foo + bar a obě fungují. Ostatní mě nezajímají. Nicméně dokážu si představit, že někdo bude mít štábní kulturu foo +bar a pak mu bude Coffee vadit (já bych s takovým člověkem třeba pracovat nechtěl).

Já s Coffee píšu čitelnější a kratší kód a jsem produktivnější. Že nepodporuje nějakou obskurní štábní kulturu není důvod, proč bych měl programovat v jazyce, který ji sice podporuje (ale já ji nepoužívám), ale budu v něm psát delší, škaredější zdroják delší dobu.

Makovec

Psal jste lépe „čitelný“ a nebo lépe „psatený“ kód? Nu, až se tento jazyk rozšíří a vám nezbyde než na velkých projektech číst i cizí zdrojáky, uvidíte s kým budete a nebudete chtít pracovat, a jestli se vás na to někdo bude ptát.

Jiří Knesl

Obojí. Čitelný a psatelný.

Pomocí Coffee jsem napsal systém, který pohání IS firmy, která má hodnotu přes 14 miliard korun. Ten zdroják není ani zdaleka trivální. Postupem času jsem si na to nabral dalšího vývojáře. Píšeme testy, děláme všechno, co se v solidním vývoji dělá. A Coffee celou tu dobu nebyl nikdy úzkým hrdlem. Naopak ohromně zrychluje vývoj.

Co se týká toho, s kým budu pracovat, vybírám si sám, jaké lidi najmu, jaký jazyk použiju a jaký framework to bude pohánět.

Makovec

Výborně. Pokud jste v pozici kdy si můžete štábní kulturu vynutit, a tím si vlastně vytvořit vlastní zúženou syntaxi jazyka, pak vám to jistě může být jedno.

Zkuste ovšem trochu poodstoupit a pochopíte co je tam za obecný problém – resp. vy to víte, jinak byste nepsal že si vybíráte jenom lidi kteří sdílejí vaši štábní kulturu.

Dundee5

Ahoj Jirko,
nemáš v plánu své zkušenosti nabité na tom projektu někde sepsat? Psal jsi v Coffee client-side i server-side? Co jsi použil jako server-side? Node.js?

Jinak mně osobně se Coffee moc líbí. Je super, jak rychle se dá naučit (5 minut je až až). Snad se časem víc rozšíří a přibude i lepší podpora do editorů.

Jiří Knesl

No v server-side jsem napsal jeden e-shop. Použil jsem node.js a Zappa. Ještě jsem to ale nespustil.

Na client-side je těch projektů víc, v podstatě ode dne, co znám coffee, používám ho na všechno.

lopata

No to potěš koště, prosím o název firmy ať vím, čemu se vyhnout. IS firmy založený na Javascriptu ve mě rozhodně nebudí důvěru.

blizz

čo je čitatelnejšie?

tento zápis:

button.click -> alert „Klik“

alebo tento zápis:

button.click(fun­ction()
{
return alert(„Klik“);
});

?

František Kučera

Bez nějakých specifických znalostí 2) a s nimi 1), ale to vynechávání závorek mi přijde vyloženě nešťastné – IMHO to čitelnost snižuje* a lepší by bylo něco jako:

button.click -> alert("Klik");

nebo spíš:

button.click -> { alert("Klik"); };

*) a těch ušetřených pár znaků za to nestojí

blizz

myslím že pre neprogramátora je rozhodne čitateľnejší a prirodzenejší 1. zápis. ale ak preferujete zátvorkové peklo tak potom sú pre vás sú C like jazyky ako stvorené.

František Kučera

Ad „pre neprogramátora“

:-)

Čelo

Doporučuji zkusit. Sám jsem byl ze začátku lehce skeptický, ale teď nedám na Coffee dopustit. Od té doby tyhle obhajoby závorkovacích orgií vůbec nechápu.

alancox

Tak tento jazyk s chutí vynechám.

Jazyk, ve kterém se trikuje namísto píše – je škoda, že to autor vůbec vymýšlel.

Srigi

Ja si naopak myslim, ze Coffee, aj ked na prvy pohlad vypada neprivetivo a akoby hadzalo polena pod nohy (vid. clanok), tak za tu namahu naucit sa ho stoji.

Doba je taka, ze vo webdev sa coraz viac logiky presuva do JS a kazde zlepsenie abstrakcie/syntaxe je len vyhodou.

blizz

syntax CoffeeScriptu je evidentne inšpirovaná jazykmi z rodiny ML pretože rovnaká chyba nastane aj v jazyku F#

let prefix = „#prvok_“
let id1 = prefix + „12“ // = „#prvok_12“
let id2 = prefix +“12″

Error 1 This value is not a function and cannot be applied C:Usersbliz­zbozDocumentsVi­sual Studio 2010ProjectsScrip­t1.fsx 3 11 Miscellaneous Files

najlepšie je otvoriť si interaktívnu konzolu http://jashkenas.github.com/coffee-script/ (Try CoffeeScript) a keď narazte na chybu tak si môžete hneď odtestovať aký JS vám z toho vylezie.

Jan Prachař

Věta „vyhodnocování operátorů je asociativní zprava“ mi vůbec nedává smysl. V uvedeném případě jde spíš o to, že implicitní závorky při volání funkce se ukončují až na konci řádku či bloku.

Enum a statická analýza kódu

Mám jednu univerzální radu pro začínající programátorty. V učení sice neexistují rychlé zkratky, ovšem tuhle radu můžete snadno začít používat a zrychlit tak tempo učení. Tou tajemnou ingrediencí je statická analýza kódu. Ukážeme si to na příkladu enum.