Tietojenkäsittelytieteessä sulku on funktio, jolla on oma ympäristö. Tässä ympäristössä on vähintään yksi sidottu muuttuja (nimi, jolla on arvo, esimerkiksi luku). Sulkeuman ympäristö pitää sidotut muuttujat muistissa sulkeuman käyttökertojen välillä.

Peter J. Landin antoi tälle ajatukselle nimen sulkeminen vuonna 1964. Scheme-ohjelmointikieli teki sulkemisista suosittuja vuoden 1975 jälkeen. Monissa sen jälkeen tehdyissä ohjelmointikielissä on sulkeumia.

Anonyymejä funktioita (funktioita, joilla ei ole nimeä) kutsutaan joskus virheellisesti sulkeumiksi. Useimmissa kielissä, joissa on anonyymejä funktioita, on myös sulkeumia. Anonyymi funktio on myös sulkeuma, jos sillä on oma ympäristö, jossa on vähintään yksi sidottu muuttuja. Anonyymi funktio, jolla ei ole omaa ympäristöä, ei ole sulkeuma. Nimetty sulkeuma ei ole nimetön.

Määritelmä ja toimintaperiaate

Sulkeuma yhdistää funktion ja sen ympäristön: se sisältää funktion koodin ja viittauksen ympäristöön, jossa funktio luotiin. Tämä ympäristö sisältää sidotut muuttujat (lokalit), joita funktio voi käyttää ja muuttaa myös sen jälkeen, kun alkuperäinen konteksti (esimerkiksi funktiokutsu) on palannut. Sulkeumat perustuvat yleensä leksikaaliseen (static) nimeämiskontekstiin — muuttujan merkitys määräytyy ohjelmakoodin rakenteen mukaan, ei ajon aikana muuttuvan kutsupinon mukaan.

Yksinkertainen esimerkki (JavaScript)

// tehtaan avulla tehdään laskuri, joka muistaa kutsukertojen määrän function makeCounter() {   let count = 0;   return function() {     count += 1;     return count;   }; }  const c = makeCounter(); console.log(c()); // 1 console.log(c()); // 2 

Tässä count elää sulkeuman ympäristössä ja sitä ei voi muuttaa suoraan ulkopuolelta — ainoa tapa on kutsua palautettua funktiota.

Esimerkki (Python)

def make_counter():     count = 0     def counter():         nonlocal count         count += 1         return count     return counter  c = make_counter() print(c())  # 1 print(c())  # 2 

Scheme-esimerkki

(define (make-counter)   (let ((count 0))     (lambda ()       (set! count (+ count 1))       count))) 

Käyttötapaukset

  • Tietojen kapselointi: sulkeumia käytetään tarjoamaan yksityinen tila julkisten rajapintojen taakse (esim. olioiden yksinkertainen korvaaja ilman luokkamekanismeja).
  • Takaisinsoitot ja tapahtumankäsittelijät: sulkeumat muistavat tarvittavat kontekstiarvot, vaikka tapahtuma käsiteltäisiin myöhemmin.
  • Osittainen sovellus ja currytys: sulkeumia käytetään sitomaan osan funktiolle annettavista argumenteista.
  • Iteraattorit ja generaattorit: tila säilyy kutsujen välillä sulkeuman avulla.

Toteutus ja muistinhallinta

Sulkeuman toteutus vaatii, että sulkeuman ympäristö säilyy elossa niin kauan kuin sulkeumaa itse käytetään. Käytännössä tämä tarkoittaa usein sitä, että muuttujat, jotka normaalisti olisivat pinolla, sijoitetaan heap-muistiin ja niitä hallitaan roskienkerääjän tai vastaavan avulla.

Kielissä ja kääntäjissä voidaan käyttää optimointeja kuten lambda-lifting (muuttujien muuttaminen funktion parametriksi) tai escape-analyysi (päätellään, tarvitseeko muuttuja jäädä heapille vai voidaan sijoittaa pinoon). Eri kielet voivat myös erilailla kopioida tai viitata suljetuille arvoille (esim. kopioida arvon vs. käyttää viittausta), mikä vaikuttaa käyttäytymiseen.

Huomioitavaa ja yleiset sudenkuopat

  • Muistin pidättäminen: sulkeuma voi pitää suuria tai odottamattomia rakenteita elossa, mikä voi johtaa muistinkäytön kasvuun, jos ei ole varovainen.
  • Loop-ongelmat: joissain kielissä, erityisesti ennen blokkiskoopin (let/const) laajaa käyttöä JavaScriptissä, silmukan sisällä luotu sulkeuma saattoi viitata samaan muuttujaan jokaisessa iteraatiossa, mikä johti odottamattomiin tuloksiin.
  • Debuggaus: sulkeumat voivat tehdä tilan seuraamisen vaikeammaksi, koska muuttujat elävät funktion eliniän ulkopuolella.
  • Syklit ja roskienkeruu: vanhemmissa järjestelmissä, joissa ei ole automaattista roskienkeräystä, sulkeumat saattoivat aiheuttaa muistivuotoja, jos niissä syntyi viitesyklejä.

Erot anonyymien funktioiden ja sulkeumien välillä

Anonyymi funktio on funktio, jolla ei ole nimeä. Sulkeuma on funktio, jolla on oma ympäristö, jossa on sidottuja muuttujia. Näin ollen anonyymi funktio voi olla sulkeuma (jos se sieppaa ympäristön), mutta se ei aina ole. Samoin nimetty funktio voi muodostaa sulkeuman, jos sen luontipaikalla on sidottuja muuttujia.

Yhteenveto: sulkeumat ovat voimakas ja yleinen abstraktio monissa ohjelmointikielissä: ne mahdollistavat funktion sisäisen tilan säilyttämisen kutsujen välillä, auttavat kapseloinnissa ja tukevat funktionaalisia ohjelmointitekniikoita, mutta vaativat myös ymmärrystä muistinhallinnasta ja mahdollisista sudenkuopista.