[{"data":1,"prerenderedAt":1244},["ShallowReactive",2],{"\u002Fposts\u002Ffunctional-options-may-not-always-form-closures":3,"posts-nav":1206},{"id":4,"title":5,"body":6,"date":1194,"description":1195,"draft":1196,"extension":1197,"meta":1198,"navigation":191,"path":1199,"seo":1200,"stem":1201,"subtitle":1202,"tags":1203,"__hash__":1205},"posts\u002Fposts\u002Ffunctional-options-may-not-always-form-closures.md","Functional options may not always form closures",{"type":7,"value":8,"toc":1189},"minimark",[9,21,24,36,39,45,48,56,69,72,378,391,394,538,543,552,557,560,569,572,664,667,670,720,723,726,751,761,781,784,787,804,813,816,827,860,864,867,968,971,988,999,1002,1024,1027,1034,1045,1048,1112,1116,1131,1134,1137,1176,1179,1182,1185],[10,11,12,13,20],"p",{},"This post builds on our ",[14,15,19],"a",{"href":16,"rel":17},"https:\u002F\u002Fbabafemikuku.com\u002Fposts\u002Fgo-closures-functional-options-pattern",[18],"nofollow","previous discussion",", where we took a deep dive into closures using the Functional Options Pattern. Please refer to it before going through this.",[10,22,23],{},"Here, we'd be taking it a little bit further.",[10,25,26,27,31,32,35],{},"We saw how something like ",[28,29,30],"code",{},"WithHost(\"localhost\")"," returned a function that still had access to ",[28,33,34],{},"host"," when that function was called later.",[10,37,38],{},"At this point, it would be tempting for you to think that:",[40,41,42],"blockquote",{},[10,43,44],{},"Functional Options = closures.",[10,46,47],{},"But...that's not quite right. Why?",[10,49,50,51,55],{},"Closures are one way to use the ",[52,53,54],"em",{},"functional options"," pattern, but they're not a requirement.",[10,57,58,59,64,65,68],{},"I discovered this myself when I was poking around the ",[14,60,63],{"href":61,"rel":62},"https:\u002F\u002Fgithub.com\u002Faws\u002Faws-sdk-go-v2",[18],"AWS SDK for Go",". It has a ",[28,66,67],{},"WithPresignExpires"," option that looks very similar to the closure-based example we discussed in my previous post, but there's something different going on underneath.",[10,70,71],{},"So, let's take a look.",[73,74,79],"pre",{"className":75,"code":76,"language":77,"meta":78,"style":78},"language-go shiki shiki-themes kanagawa-lotus","func generatePresignedURL(s3Client *s3.Client, bucket, key string, expireTime time.Duration) (string, error) {\n    presignClient := s3.NewPresignClient(s3Client)\n\n    objectInput := &s3.GetObjectInput{\n        Bucket: &bucket,\n        Key:    &key,\n    }\n\n    presignedHTTPRequest, err := presignClient.PresignGetObject(context.Background(), objectInput, s3.WithPresignExpires(expireTime))\n    if err != nil {\n        return \"\", err\n    }\n\n    return presignedHTTPRequest.URL, nil\n}\n","go","",[28,80,81,161,186,193,214,231,247,253,258,311,328,343,348,353,372],{"__ignoreMap":78},[82,83,86,90,94,98,102,106,110,113,116,119,122,124,127,130,132,135,138,140,143,146,149,151,153,156,158],"span",{"class":84,"line":85},"line",1,[82,87,89],{"class":88},"spXry","func",[82,91,93],{"class":92},"sRuoB"," generatePresignedURL",[82,95,97],{"class":96},"soh45","(",[82,99,101],{"class":100},"sE3-p","s3Client ",[82,103,105],{"class":104},"sXttF","*",[82,107,109],{"class":108},"sISTA","s3",[82,111,112],{"class":96},".",[82,114,115],{"class":108},"Client",[82,117,118],{"class":96},",",[82,120,121],{"class":100}," bucket",[82,123,118],{"class":96},[82,125,126],{"class":100}," key ",[82,128,129],{"class":88},"string",[82,131,118],{"class":96},[82,133,134],{"class":100}," expireTime ",[82,136,137],{"class":108},"time",[82,139,112],{"class":96},[82,141,142],{"class":108},"Duration",[82,144,145],{"class":96},")",[82,147,148],{"class":96}," (",[82,150,129],{"class":88},[82,152,118],{"class":96},[82,154,155],{"class":88}," error",[82,157,145],{"class":96},[82,159,160],{"class":96}," {\n",[82,162,164,167,170,173,175,178,180,183],{"class":84,"line":163},2,[82,165,166],{"class":100},"    presignClient ",[82,168,169],{"class":104},":=",[82,171,172],{"class":100}," s3",[82,174,112],{"class":96},[82,176,177],{"class":92},"NewPresignClient",[82,179,97],{"class":96},[82,181,182],{"class":100},"s3Client",[82,184,185],{"class":96},")\n",[82,187,189],{"class":84,"line":188},3,[82,190,192],{"emptyLinePlaceholder":191},true,"\n",[82,194,196,199,201,204,206,208,211],{"class":84,"line":195},4,[82,197,198],{"class":100},"    objectInput ",[82,200,169],{"class":104},[82,202,203],{"class":104}," &",[82,205,109],{"class":108},[82,207,112],{"class":96},[82,209,210],{"class":108},"GetObjectInput",[82,212,213],{"class":96},"{\n",[82,215,217,220,223,225,228],{"class":84,"line":216},5,[82,218,219],{"class":104},"        Bucket",[82,221,222],{"class":96},":",[82,224,203],{"class":104},[82,226,227],{"class":100},"bucket",[82,229,230],{"class":96},",\n",[82,232,234,237,239,242,245],{"class":84,"line":233},6,[82,235,236],{"class":104},"        Key",[82,238,222],{"class":96},[82,240,241],{"class":104},"    &",[82,243,244],{"class":100},"key",[82,246,230],{"class":96},[82,248,250],{"class":84,"line":249},7,[82,251,252],{"class":96},"    }\n",[82,254,256],{"class":84,"line":255},8,[82,257,192],{"emptyLinePlaceholder":191},[82,259,261,264,266,269,271,274,276,279,281,284,286,289,292,295,297,299,301,303,305,308],{"class":84,"line":260},9,[82,262,263],{"class":100},"    presignedHTTPRequest",[82,265,118],{"class":96},[82,267,268],{"class":100}," err ",[82,270,169],{"class":104},[82,272,273],{"class":100}," presignClient",[82,275,112],{"class":96},[82,277,278],{"class":92},"PresignGetObject",[82,280,97],{"class":96},[82,282,283],{"class":100},"context",[82,285,112],{"class":96},[82,287,288],{"class":92},"Background",[82,290,291],{"class":96},"(),",[82,293,294],{"class":100}," objectInput",[82,296,118],{"class":96},[82,298,172],{"class":100},[82,300,112],{"class":96},[82,302,67],{"class":92},[82,304,97],{"class":96},[82,306,307],{"class":100},"expireTime",[82,309,310],{"class":96},"))\n",[82,312,314,317,319,322,326],{"class":84,"line":313},10,[82,315,316],{"class":88},"    if",[82,318,268],{"class":100},[82,320,321],{"class":104},"!=",[82,323,325],{"class":324},"sYIP1"," nil",[82,327,160],{"class":96},[82,329,331,334,338,340],{"class":84,"line":330},11,[82,332,333],{"class":88},"        return",[82,335,337],{"class":336},"sKHqS"," \"\"",[82,339,118],{"class":96},[82,341,342],{"class":100}," err\n",[82,344,346],{"class":84,"line":345},12,[82,347,252],{"class":96},[82,349,351],{"class":84,"line":350},13,[82,352,192],{"emptyLinePlaceholder":191},[82,354,356,359,362,364,367,369],{"class":84,"line":355},14,[82,357,358],{"class":88},"    return",[82,360,361],{"class":100}," presignedHTTPRequest",[82,363,112],{"class":96},[82,365,366],{"class":100},"URL",[82,368,118],{"class":96},[82,370,371],{"class":324}," nil\n",[82,373,375],{"class":84,"line":374},15,[82,376,377],{"class":96},"}\n",[10,379,380,381,383,384,386,387,390],{},"Here, I was working on a function that returns presigned URL for an object in an s3 bucket, so I needed to use ",[28,382,278],{}," from the SDK. I want you to focus on the last argument that ",[28,385,278],{}," takes. Notice the ",[28,388,389],{},"With..."," pattern.",[10,392,393],{},"You might expect that it returns a closure just like we discussed in the previous post. But notice what I found when I poked around:",[73,395,397],{"className":75,"code":396,"language":77,"meta":78,"style":78},"func WithPresignExpires(dur time.Duration) func(*PresignOptions) {\n    return withPresignExpires(dur).options\n}\n\ntype withPresignExpires time.Duration\n\nfunc (w withPresignExpires) options(o *PresignOptions) {\n    o.Expires = time.Duration(w)\n}\n",[28,398,399,433,451,455,459,474,478,508,534],{"__ignoreMap":78},[82,400,401,403,406,408,411,413,415,417,419,422,424,426,429,431],{"class":84,"line":85},[82,402,89],{"class":88},[82,404,405],{"class":92}," WithPresignExpires",[82,407,97],{"class":96},[82,409,410],{"class":100},"dur ",[82,412,137],{"class":108},[82,414,112],{"class":96},[82,416,142],{"class":108},[82,418,145],{"class":96},[82,420,421],{"class":88}," func",[82,423,97],{"class":96},[82,425,105],{"class":104},[82,427,428],{"class":108},"PresignOptions",[82,430,145],{"class":96},[82,432,160],{"class":96},[82,434,435,437,440,442,445,448],{"class":84,"line":163},[82,436,358],{"class":88},[82,438,439],{"class":92}," withPresignExpires",[82,441,97],{"class":96},[82,443,444],{"class":100},"dur",[82,446,447],{"class":96},").",[82,449,450],{"class":100},"options\n",[82,452,453],{"class":84,"line":188},[82,454,377],{"class":96},[82,456,457],{"class":84,"line":195},[82,458,192],{"emptyLinePlaceholder":191},[82,460,461,464,466,469,471],{"class":84,"line":216},[82,462,463],{"class":88},"type",[82,465,439],{"class":108},[82,467,468],{"class":108}," time",[82,470,112],{"class":96},[82,472,473],{"class":108},"Duration\n",[82,475,476],{"class":84,"line":233},[82,477,192],{"emptyLinePlaceholder":191},[82,479,480,482,484,487,490,492,495,497,500,502,504,506],{"class":84,"line":249},[82,481,89],{"class":88},[82,483,148],{"class":96},[82,485,486],{"class":100},"w ",[82,488,489],{"class":108},"withPresignExpires",[82,491,145],{"class":96},[82,493,494],{"class":92}," options",[82,496,97],{"class":96},[82,498,499],{"class":100},"o ",[82,501,105],{"class":104},[82,503,428],{"class":108},[82,505,145],{"class":96},[82,507,160],{"class":96},[82,509,510,513,515,518,521,523,525,527,529,532],{"class":84,"line":255},[82,511,512],{"class":100},"    o",[82,514,112],{"class":96},[82,516,517],{"class":100},"Expires ",[82,519,520],{"class":104},"=",[82,522,468],{"class":100},[82,524,112],{"class":96},[82,526,142],{"class":92},[82,528,97],{"class":96},[82,530,531],{"class":100},"w",[82,533,185],{"class":96},[82,535,536],{"class":84,"line":260},[82,537,377],{"class":96},[10,539,540,542],{},[28,541,67],{}," doesn't return a closure!",[10,544,545,546,548,549,551],{},"So, what does it return? We learnt that closures help functions remember stuff in their lexical scope right, so how does ",[28,547,444],{}," survive after ",[28,550,67],{}," is eventually called? There's no closure here, so what's up?",[553,554,556],"h2",{"id":555},"enter-methods-as-values","Enter Methods as Values",[10,558,559],{},"We'd come back to functional options. Let's take a little detour if you don't mind.",[10,561,562,563,568],{},"In Go, ",[14,564,567],{"href":565,"rel":566},"https:\u002F\u002Fgo.dev\u002Ftour\u002Fmethods\u002F1",[18],"methods"," are simply functions that are associated with a type.",[10,570,571],{},"For example:",[73,573,575],{"className":75,"code":574,"language":77,"meta":78,"style":78},"\u002F\u002F a type\ntype Server struct {\n    host string\n}\n\n\u002F\u002F a method\nfunc (s *Server) setHost(host string) {\n    s.host = host\n}\n",[28,576,577,583,595,603,607,611,616,646,660],{"__ignoreMap":78},[82,578,579],{"class":84,"line":85},[82,580,582],{"class":581},"sHb24","\u002F\u002F a type\n",[82,584,585,587,590,593],{"class":84,"line":163},[82,586,463],{"class":88},[82,588,589],{"class":108}," Server",[82,591,592],{"class":88}," struct",[82,594,160],{"class":96},[82,596,597,600],{"class":84,"line":188},[82,598,599],{"class":104},"    host",[82,601,602],{"class":88}," string\n",[82,604,605],{"class":84,"line":195},[82,606,377],{"class":96},[82,608,609],{"class":84,"line":216},[82,610,192],{"emptyLinePlaceholder":191},[82,612,613],{"class":84,"line":233},[82,614,615],{"class":581},"\u002F\u002F a method\n",[82,617,618,620,622,625,627,630,632,635,637,640,642,644],{"class":84,"line":249},[82,619,89],{"class":88},[82,621,148],{"class":96},[82,623,624],{"class":100},"s ",[82,626,105],{"class":104},[82,628,629],{"class":108},"Server",[82,631,145],{"class":96},[82,633,634],{"class":92}," setHost",[82,636,97],{"class":96},[82,638,639],{"class":100},"host ",[82,641,129],{"class":88},[82,643,145],{"class":96},[82,645,160],{"class":96},[82,647,648,651,653,655,657],{"class":84,"line":255},[82,649,650],{"class":100},"    s",[82,652,112],{"class":96},[82,654,639],{"class":100},[82,656,520],{"class":104},[82,658,659],{"class":100}," host\n",[82,661,662],{"class":84,"line":260},[82,663,377],{"class":96},[10,665,666],{},"Notice it looks like a function but with some special kind of backpack (called it's receiver).",[10,668,669],{},"Normally, we expect to call the method directly like so:",[73,671,673],{"className":75,"code":672,"language":77,"meta":78,"style":78},"\u002F\u002F type initialized\nserver := &Server{}\n\n\u002F\u002F you have called me now\nserver.setHost(\"localhost\")\n",[28,674,675,680,694,698,703],{"__ignoreMap":78},[82,676,677],{"class":84,"line":85},[82,678,679],{"class":581},"\u002F\u002F type initialized\n",[82,681,682,685,687,689,691],{"class":84,"line":163},[82,683,684],{"class":100},"server ",[82,686,169],{"class":104},[82,688,203],{"class":104},[82,690,629],{"class":108},[82,692,693],{"class":96},"{}\n",[82,695,696],{"class":84,"line":188},[82,697,192],{"emptyLinePlaceholder":191},[82,699,700],{"class":84,"line":195},[82,701,702],{"class":581},"\u002F\u002F you have called me now\n",[82,704,705,708,710,713,715,718],{"class":84,"line":216},[82,706,707],{"class":100},"server",[82,709,112],{"class":96},[82,711,712],{"class":92},"setHost",[82,714,97],{"class":96},[82,716,717],{"class":336},"\"localhost\"",[82,719,185],{"class":96},[10,721,722],{},"But, hey! There's something else we can do.",[10,724,725],{},"We can take the method and bind it to it's receiver, and then assign it to a variable rather than call it now:",[73,727,729],{"className":75,"code":728,"language":77,"meta":78,"style":78},"\u002F\u002F you can invoke me later\nsetHost := server.setHost\n",[28,730,731,736],{"__ignoreMap":78},[82,732,733],{"class":84,"line":85},[82,734,735],{"class":581},"\u002F\u002F you can invoke me later\n",[82,737,738,741,743,746,748],{"class":84,"line":163},[82,739,740],{"class":100},"setHost ",[82,742,169],{"class":104},[82,744,745],{"class":100}," server",[82,747,112],{"class":96},[82,749,750],{"class":100},"setHost\n",[10,752,753,754,756,757,760],{},"Now ",[28,755,712],{}," is a variable that holds a ",[52,758,759],{},"method value"," that we can call later:",[73,762,764],{"className":75,"code":763,"language":77,"meta":78,"style":78},"\u002F\u002F invoking the method value we stored\nsetHost(\"localhost\")\n",[28,765,766,771],{"__ignoreMap":78},[82,767,768],{"class":84,"line":85},[82,769,770],{"class":581},"\u002F\u002F invoking the method value we stored\n",[82,772,773,775,777,779],{"class":84,"line":163},[82,774,712],{"class":92},[82,776,97],{"class":96},[82,778,717],{"class":336},[82,780,185],{"class":96},[10,782,783],{},"So what's going on here?",[10,785,786],{},"When we write:",[73,788,790],{"className":75,"code":789,"language":77,"meta":78,"style":78},"setHost := server.setHost\n",[28,791,792],{"__ignoreMap":78},[82,793,794,796,798,800,802],{"class":84,"line":85},[82,795,740],{"class":100},[82,797,169],{"class":104},[82,799,745],{"class":100},[82,801,112],{"class":96},[82,803,750],{"class":100},[10,805,806,807,809,810,812],{},"the ",[28,808,707],{}," struct value is already attached\u002Fbinded\u002Fglued to the ",[28,811,712],{}," method we defined earlier.",[10,814,815],{},"That's what a method value is: a method with its receiver already bound to it, which you can call later.",[40,817,818],{},[10,819,820,821,823,824,826],{},"Note that the name of the variable that keeps the method value can be anything. But I think it just makes sense to name it according to the method name, so when you call it later, you easily know what you're calling. That's why I named the variable ",[28,822,712],{}," to match the method ",[28,825,712],{},". But you could have done:",[73,828,830],{"className":75,"code":829,"language":77,"meta":78,"style":78},"anotherName := server.setHost\n\nanotherName(\"localhost\")\n",[28,831,832,845,849],{"__ignoreMap":78},[82,833,834,837,839,841,843],{"class":84,"line":85},[82,835,836],{"class":100},"anotherName ",[82,838,169],{"class":104},[82,840,745],{"class":100},[82,842,112],{"class":96},[82,844,750],{"class":100},[82,846,847],{"class":84,"line":163},[82,848,192],{"emptyLinePlaceholder":191},[82,850,851,854,856,858],{"class":84,"line":188},[82,852,853],{"class":92},"anotherName",[82,855,97],{"class":96},[82,857,717],{"class":336},[82,859,185],{"class":96},[553,861,863],{"id":862},"back-to-the-aws-example-shall-we","Back to the AWS example, shall we?!",[10,865,866],{},"Now let's look at this line again:",[73,868,870],{"className":75,"code":869,"language":77,"meta":78,"style":78},"...\nreturn withPresignExpires(dur).options\n}\n\ntype withPresignExpires time.Duration\n\nfunc (w withPresignExpires) options(o *PresignOptions) {\n    o.Expires = time.Duration(w)\n}\n",[28,871,872,877,892,896,900,912,916,942,964],{"__ignoreMap":78},[82,873,874],{"class":84,"line":85},[82,875,876],{"class":104},"...\n",[82,878,879,882,884,886,888,890],{"class":84,"line":163},[82,880,881],{"class":88},"return",[82,883,439],{"class":92},[82,885,97],{"class":96},[82,887,444],{"class":100},[82,889,447],{"class":96},[82,891,450],{"class":100},[82,893,894],{"class":84,"line":188},[82,895,377],{"class":100},[82,897,898],{"class":84,"line":195},[82,899,192],{"emptyLinePlaceholder":191},[82,901,902,904,906,908,910],{"class":84,"line":216},[82,903,463],{"class":88},[82,905,439],{"class":108},[82,907,468],{"class":108},[82,909,112],{"class":96},[82,911,473],{"class":108},[82,913,914],{"class":84,"line":233},[82,915,192],{"emptyLinePlaceholder":191},[82,917,918,920,922,924,926,928,930,932,934,936,938,940],{"class":84,"line":249},[82,919,89],{"class":88},[82,921,148],{"class":96},[82,923,486],{"class":100},[82,925,489],{"class":108},[82,927,145],{"class":96},[82,929,494],{"class":92},[82,931,97],{"class":96},[82,933,499],{"class":100},[82,935,105],{"class":104},[82,937,428],{"class":108},[82,939,145],{"class":96},[82,941,160],{"class":96},[82,943,944,946,948,950,952,954,956,958,960,962],{"class":84,"line":255},[82,945,512],{"class":100},[82,947,112],{"class":96},[82,949,517],{"class":100},[82,951,520],{"class":104},[82,953,468],{"class":100},[82,955,112],{"class":96},[82,957,142],{"class":92},[82,959,97],{"class":96},[82,961,531],{"class":100},[82,963,185],{"class":96},[82,965,966],{"class":84,"line":260},[82,967,377],{"class":96},[10,969,970],{},"We can break it down.",[10,972,973,974,977,978,980,981,984,985,987],{},"First, ",[28,975,976],{},"withPresignExpires(dur)"," converts the ",[28,979,444],{}," value of type ",[28,982,983],{},"time.Duration"," to a value of type ",[28,986,489],{}," (a custom type).",[10,989,990,991,994,995,998],{},"And when we write ",[28,992,993],{},"withPresignExpires(dur).options"," we're simply binding the ",[28,996,997],{},"options"," method to the value we just converted (a.k.a it's receiver), which we can call later.",[10,1000,1001],{},"So conceptually:",[73,1003,1005],{"className":75,"code":1004,"language":77,"meta":78,"style":78},"option := withPresignExpires(dur).options\n",[28,1006,1007],{"__ignoreMap":78},[82,1008,1009,1012,1014,1016,1018,1020,1022],{"class":84,"line":85},[82,1010,1011],{"class":100},"option ",[82,1013,169],{"class":104},[82,1015,439],{"class":92},[82,1017,97],{"class":96},[82,1019,444],{"class":100},[82,1021,447],{"class":96},[82,1023,450],{"class":100},[10,1025,1026],{},"means:",[10,1028,1029,1030,1033],{},"\"Keep this method value inside an ",[28,1031,1032],{},"option"," variable, so I can call it later.\"",[10,1035,1036,1037,1039,1040,1042,1043,112],{},"And when it runs, the receiver ",[28,1038,531],{}," is still the ",[28,1041,489],{}," value created from ",[28,1044,444],{},[10,1046,1047],{},"Notice the difference between calling the method immediatley and storing, then calling later:",[73,1049,1051],{"className":75,"code":1050,"language":77,"meta":78,"style":78},"\u002F\u002F called immediately\nwithPresignExpires(dur).options(presignOptions)\n\n\u002F\u002F saved in a variable and called later\noption := withPresignExpires(dur).options\noption(presignOptions)\n",[28,1052,1053,1058,1077,1081,1086,1102],{"__ignoreMap":78},[82,1054,1055],{"class":84,"line":85},[82,1056,1057],{"class":581},"\u002F\u002F called immediately\n",[82,1059,1060,1062,1064,1066,1068,1070,1072,1075],{"class":84,"line":163},[82,1061,489],{"class":92},[82,1063,97],{"class":96},[82,1065,444],{"class":100},[82,1067,447],{"class":96},[82,1069,997],{"class":92},[82,1071,97],{"class":96},[82,1073,1074],{"class":100},"presignOptions",[82,1076,185],{"class":96},[82,1078,1079],{"class":84,"line":188},[82,1080,192],{"emptyLinePlaceholder":191},[82,1082,1083],{"class":84,"line":195},[82,1084,1085],{"class":581},"\u002F\u002F saved in a variable and called later\n",[82,1087,1088,1090,1092,1094,1096,1098,1100],{"class":84,"line":216},[82,1089,1011],{"class":100},[82,1091,169],{"class":104},[82,1093,439],{"class":92},[82,1095,97],{"class":96},[82,1097,444],{"class":100},[82,1099,447],{"class":96},[82,1101,450],{"class":100},[82,1103,1104,1106,1108,1110],{"class":84,"line":233},[82,1105,1032],{"class":92},[82,1107,97],{"class":96},[82,1109,1074],{"class":100},[82,1111,185],{"class":96},[553,1113,1115],{"id":1114},"lets-call-it-a-wrap","Let's call it a wrap",[10,1117,1118,1119,1121,1122,1124,1125,1127,1128,1130],{},"Unlike our previous closure example, where reference to a value is captured inside an enclosing function. Here, ",[28,1120,444],{}," isn't being captured from an enclosing function scope. The ",[28,1123,444],{}," value became the receiver of the ",[28,1126,1032],{}," method. And anything we were ready to call the method value, the ",[28,1129,444],{}," value (method receiver) we created is still alive and would be referenced by the method.",[10,1132,1133],{},"So the key lesson here is that: closures remember variables from an enclosing scope, while method values carry around their receivers with them.",[10,1135,1136],{},"Both of them allow you produce a function that you can pass around, remember values, and call later. And that's exactly what the functional optional pattern needs.",[1138,1139,1140,1153],"table",{},[1141,1142,1143],"thead",{},[1144,1145,1146,1150],"tr",{},[1147,1148,1149],"th",{},"Closure",[1147,1151,1152],{},"Method value",[1154,1155,1156,1165],"tbody",{},[1144,1157,1158,1162],{},[1159,1160,1161],"td",{},"Function remembers variables from an enclosing scope",[1159,1163,1164],{},"Function has a receiver attached to it",[1144,1166,1167,1172],{},[1159,1168,1169],{},[28,1170,1171],{},"func(s *Server) { s.host = host }",[1159,1173,1174],{},[28,1175,993],{},[1177,1178],"br",{},[10,1180,1181],{},"The functional options pattern doesn't require closures specifically. It simply requires functions that can be used to configure something. Closures and method values are just two different ways to produce those functions.",[10,1183,1184],{},"See you in the next one. :)",[1186,1187,1188],"style",{},"html pre.shiki code .spXry, html code.shiki .spXry{--shiki-default:#624C83}html pre.shiki code .sRuoB, html code.shiki .sRuoB{--shiki-default:#4D699B}html pre.shiki code .soh45, html code.shiki .soh45{--shiki-default:#4E8CA2}html pre.shiki code .sE3-p, html code.shiki .sE3-p{--shiki-default:#545464}html pre.shiki code .sXttF, html code.shiki .sXttF{--shiki-default:#77713F}html pre.shiki code .sISTA, html code.shiki .sISTA{--shiki-default:#597B75}html pre.shiki code .sYIP1, html code.shiki .sYIP1{--shiki-default:#CC6D00}html pre.shiki code .sKHqS, html code.shiki .sKHqS{--shiki-default:#6F894E}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .sHb24, html code.shiki .sHb24{--shiki-default:#716E61}",{"title":78,"searchDepth":163,"depth":163,"links":1190},[1191,1192,1193],{"id":555,"depth":163,"text":556},{"id":862,"depth":163,"text":863},{"id":1114,"depth":163,"text":1115},"2026-10-06","This post builds on our previous discussion, where we took a deep dive into closures using the Functional Options Pattern. Please refer to it before going through this.",false,"md",{},"\u002Fposts\u002Ffunctional-options-may-not-always-form-closures",{"title":5,"description":1195},"posts\u002Ffunctional-options-may-not-always-form-closures",null,[1204],"golang","p58T6rxQo758ORAgP2XLefcBjk9gzX9tt0X8Ih1K1KU",[1207,1208,1212,1216,1220,1224,1228,1232,1236,1240],{"path":1199,"title":5,"date":1194},{"path":1209,"title":1210,"date":1211},"\u002Fposts\u002Fgo-closures-functional-options-pattern","Understanding closures in Go through the functional options pattern","2026-09-25",{"path":1213,"title":1214,"date":1215},"\u002Fposts\u002Fgoing-with-go","Going with Go","2026-09-14",{"path":1217,"title":1218,"date":1219},"\u002Fposts\u002Fcollecting-blogs","Collecting blogs","2026-09-10",{"path":1221,"title":1222,"date":1223},"\u002Fposts\u002Fhello-world","Hello, world!","2026-08-01",{"path":1225,"title":1226,"date":1227},"\u002Fposts\u002Fwhy-my-first-react-app-should-have-been-tic-tac-toe","Why my first React app should have been tic-tac-toe","2025-07-02",{"path":1229,"title":1230,"date":1231},"\u002Fposts\u002Ftyped-and-tested","Typed and tested","2025-05-29",{"path":1233,"title":1234,"date":1235},"\u002Fposts\u002Fforms-without-the-stress","Forms without the stress: React hook form does it best!","2025-03-16",{"path":1237,"title":1238,"date":1239},"\u002Fposts\u002Fdata-fetching","Data fetching in React","2025-01-26",{"path":1241,"title":1242,"date":1243},"\u002Fposts\u002F2024-in-review","2024 in review as a frontend engineer","2024-12-31",1791245350719]