[{"data":1,"prerenderedAt":4325},["ShallowReactive",2],{"/engineering-logs/distributed-counters":3,"/engineering-logs/distributed-counters--related":967},{"id":4,"title":5,"author":6,"body":7,"date":951,"description":952,"extension":953,"image_url":954,"meta":955,"navigation":406,"original_url":956,"path":957,"readTime":958,"seo":959,"stem":960,"tags":961,"__hash__":966},"engineeringLogs/engineering-logs/distributed-counters.md","On the Topic of Making Simple Useful Things (A Distributed Counter)","David Oyinbo",{"type":8,"value":9,"toc":941},"minimark",[10,16,20,24,29,33,37,42,46,49,52,55,58,66,69,72,75,79,82,85,88,95,98,101,104,108,111,114,117,120,123,126,129,133,136,139,142,145,148,151,154,158,161,164,167,177,180,183,186,193,196,200,203,206,209,220,223,226,229,233,236,245,248,271,274,277,280,284,287,298,301,327,330,338,341,567,570,573,576,670,673,676,679,759,762,765,768,917,920,928,931,934,937],[11,12],"content-time-detail",{"className":13,"date":15},[14],"mb-2","2026-06-14",[17,18,5],"h1",{"id":19},"on-the-topic-of-making-simple-useful-things-a-distributed-counter",[21,22,23],"p",{},"Counting things across multiple servers sounds trivial. It is not.",[25,26],"div",{"className":27},[28],"mb-3",[30,31],"tag-list",{":tags":32},"[\"Rust\", \"Distributed Systems\", \"Redis\", \"Engineering\", \"Counters\"]",[25,34],{"className":35},[36],"mb-8",[38,39,41],"h2",{"id":40},"the-basic-problem","The Basic Problem",[25,43],{"className":44},[45],"mb-4",[21,47,48],{},"On a single server, counting is barely a problem. Something happens, you bump a number in memory, and you move on. The trouble starts the moment there is a second server.",[25,50],{"className":51},[45],[21,53,54],{},"The thing people forget is that an increment isn't one operation. It's three: read the current value, add one, write it back. On one machine those three steps run back to back and nobody notices. On two machines they interleave. Both servers read 41, both add one, both write 42. You did two increments and the counter only moved by one. The update didn't go anywhere. It was quietly overwritten.",[25,56],{"className":57},[45],[21,59,60,61,65],{},"The usual fix is to hand the problem to something that can serialise the writes for you, and that something is almost always Redis. Redis is single threaded. It runs one command at a time, full stop, and it gives you operations like ",[62,63,64],"code",{},"HINCRBY"," that fold the read, the add, and the write into a single atomic step and hand you the new value back. There is no gap for a second writer to slip into.",[25,67],{"className":68},[45],[21,70,71],{},"For most things, that is the entire story. Wrap the increment in a small Lua script so the read and the write travel together, point every server at the same Redis, and the count stays correct no matter how many servers you are running. You can stop here and be fine.",[25,73],{"className":74},[36],[38,76,78],{"id":77},"accuracy-vs-throughput","Accuracy vs Throughput",[25,80],{"className":81},[45],[21,83,84],{},"The catch is the network. Every increment is now a round trip to Redis, and on a lightly loaded system you will never feel it. Start counting page impressions or API calls, things that happen thousands of times a second, and a Redis call per event becomes the most expensive thing your code does.",[25,86],{"className":87},[45],[21,89,90,91,94],{},"The way out is to stop writing on every increment. Keep a small buffer in memory, a map from key to the delta you owe Redis, and add to it locally. Then on a fixed interval, flush the whole thing in one pipelined batch and start over. Redis traffic drops by orders of magnitude, and ",[62,92,93],{},"inc"," stops being a network call. It becomes an in memory atomic add, which finishes in well under a microsecond.",[25,96],{"className":97},[45],[21,99,100],{},"You do not get that for free, of course. You have traded immediate consistency for eventual consistency. Increment a counter on server A, immediately read it from server B, and B can hand you a stale total because it has not flushed yet. Reads stay consistent within a single process, since you just add the local buffer to whatever Redis already has, but across servers there is a window, up to one flush interval wide, where the totals disagree. For analytics that is a perfectly fine trade. For billing or inventory it absolutely is not.",[25,102],{"className":103},[36],[38,105,107],{"id":106},"when-a-global-counter-is-not-enough","When a Global Counter Is Not Enough",[25,109],{"className":110},[45],[21,112,113],{},"The two patterns above cover a surprising amount of ground. There is one class of problem they do not touch, though, and it took me a while to see why.",[25,115],{"className":116},[45],[21,118,119],{},"Say you want to know how many WebSocket connections are open across the whole cluster right now. A global counter seems perfect: increment when a connection opens, decrement when it closes, read the total whenever you like. And it works, right up until a server crashes. Server A dies with 500 connections open. Those connections are gone, but nobody got to run the 500 decrements. The global count is now 500 too high, and it stays that way forever, because the only process that knew about those connections is no longer running.",[25,121],{"className":122},[45],[21,124,125],{},"You can try to paper over this. Reset the count on startup, and you race every other server that is also starting up. Run a periodic reconciliation job, and now you have an extra moving part plus a window where the number is just wrong. I tried both in my head and neither one sat right.",[25,127],{"className":128},[36],[38,130,132],{"id":131},"owning-a-slice","Owning a Slice",[25,134],{"className":135},[45],[21,137,138],{},"The cleaner idea is to stop sharing one number. Give every server its own slice of the counter instead.",[25,140],{"className":141},[45],[21,143,144],{},"Each process gets a UUID when it starts. When it increments, it writes to a key that belongs to it and nobody else, and it bumps the shared cumulative in the same atomic step. Because no two processes ever write to the same slice, there is nothing to coordinate. Each one is the sole authority on its own contribution, and the cumulative is just kept in lockstep as the sum of every live slice. No locks, no fighting over a single field.",[25,146],{"className":147},[45],[21,149,150],{},"It also changes what a read can tell you. Every read comes back with two numbers: the cluster wide cumulative and this instance's own slice. More often than not that is exactly the pair you want, the global total on a dashboard while still knowing how much of it this particular box is responsible for.",[25,152],{"className":153},[36],[38,155,157],{"id":156},"the-dead-instance-problem","The Dead Instance Problem",[25,159],{"className":160},[45],[21,162,163],{},"Slicing fixes the coordination problem. It does not fix the dead instance problem, not yet. If server A dies, its slice is still sitting in Redis, and the cumulative still counts it.",[25,165],{"className":166},[45],[21,168,169,170,172,173,176],{},"What I settled on is heartbeats, but not the version you might expect. There is no TTL key per instance. Instead there is a single sorted set per counter, where each member is an instance's UUID and its score is the last time that instance was seen. Every operation an instance runs, every ",[62,171,93],{},", every ",[62,174,175],{},"get",", anything that touches Redis, also stamps its own score with the current time. So liveness rides along on work the instance was already doing. As long as a process keeps doing anything at all, it keeps itself alive in that set.",[25,178],{"className":179},[45],[21,181,182],{},"The cleanup is the part I am happiest with: it is not a background job at all. It is a side effect of ordinary operations. Whenever any instance touches a counter, the script first range scans the sorted set for members whose last seen timestamp is older than the threshold. For each dead instance it finds, it subtracts that instance's contribution back out of the cumulative, deletes its slice, and drops it from the set. The survivors clean up after the dead, collectively, with no coordinator and no scheduled task. A crashed server's contribution just evaporates the next time anyone looks.",[25,184],{"className":185},[45],[21,187,188,189,192],{},"How long older than the threshold means is up to you, ",[62,190,191],{},"dead_instance_threshold_ms",", thirty seconds by default. Turn it down and you react to crashes faster but start punishing instances that merely went quiet for a moment over a flaky network. Thirty seconds has been a sane middle for everything I have thrown at it.",[25,194],{"className":195},[36],[38,197,199],{"id":198},"coordinating-a-reset","Coordinating a Reset",[25,201],{"className":202},[45],[21,204,205],{},"One problem left. Suppose you want to reset a counter to a specific value across the whole cluster, set the global total to 100. Each instance still has its own slice lying around, so the next time anyone reads and the cumulative gets reconciled against those slices, your clean 100 turns back into garbage.",[25,207],{"className":208},[45],[21,210,211,212,215,216,219],{},"I solved this with an epoch, a version number per counter, living in Redis, that marks the current era. The coordinating operations, ",[62,213,214],{},"set"," and ",[62,217,218],{},"del",", bump the epoch when they run. Every instance remembers the epoch it last saw locally, and before it does anything it checks whether Redis has moved on. If the epoch changed, the instance zeroes its own slice before touching the counter. After a reset, every instance independently realises it is in a new era and starts from a clean baseline. No broadcast, no instance ever has to talk to another directly.",[25,221],{"className":222},[45],[21,224,225],{},"Recovery from a network blip falls out of the same mechanism for free. If a server drops off and comes back holding increments it never managed to flush, it should only replay them if the epoch has not changed. If it has, the buffered data belongs to a previous era and gets thrown away. One check, and recovery is safe without a separate reconciliation protocol bolted on top.",[25,227],{"className":228},[36],[38,230,232],{"id":231},"the-lax-layer-again","The Lax Layer, Again",[25,234],{"className":235},[45],[21,237,238,239,215,241,244],{},"The buffering trick from the basic counter applies here too. If you are tracking something that fires thousands of times a second, you still do not want a Redis call per event just because the counter happens to be instance aware. So the lax instance aware counter buffers ",[62,240,93],{},[62,242,243],{},"dec"," locally the same way the plain lax counter does. The only difference is that when it flushes, the writes land in this instance's slice instead of a shared key.",[25,246],{"className":247},[45],[21,249,250,251,253,254,253,256,258,259,262,263,253,265,258,267,270],{},"The warm path never leaves memory. ",[62,252,93],{},", ",[62,255,243],{},[62,257,175],{},", and ",[62,260,261],{},"set_on_instance"," all read and write the local buffer and return immediately. The operations that have to be globally consistent, ",[62,264,214],{},[62,266,218],{},[62,268,269],{},"clear",", flush whatever is pending first and then hand off to the strict implementation. So the latency promise has a footnote: warm path calls finish in well under a microsecond, but anything that must be true across the whole cluster pays for a Redis round trip. That is the honest version, and I would rather state it than hide it.",[25,272],{"className":273},[45],[21,275,276],{},"The flushing itself runs on a Tokio task that holds a weak reference back to the counter. When you drop the counter, the weak reference cannot upgrade, the task notices on its next tick, and it shuts itself down. There is nothing to stop manually and nothing to leak.",[25,278],{"className":279},[36],[38,281,283],{"id":282},"i-built-this-in-distkit","I Built This in distkit",[25,285],{"className":286},[45],[21,288,289,290,297],{},"I needed every one of these behaviours for a realtime platform I have been building. Rather than let the implementation rot inside that one project, I pulled it out into a standalone Rust crate: ",[291,292,296],"a",{"href":293,"rel":294},"https://davidoyinbo.com/projects/distkit",[295],"nofollow","distkit",".",[25,299],{"className":300},[45],[21,302,303,304,253,307,253,310,258,313,316,317,320,321,326],{},"It ships four counter types, ",[62,305,306],{},"StrictCounter",[62,308,309],{},"LaxCounter",[62,311,312],{},"StrictInstanceAwareCounter",[62,314,315],{},"LaxInstanceAwareCounter",", and each one maps cleanly onto a decision from this post. The crate is ",[62,318,319],{},"#![forbid(unsafe_code)]",", with 194 tests and 77 runnable doc examples keeping me honest. It also pulls in ",[291,322,325],{"href":323,"rel":324},"https://davidoyinbo.com/projects/trypema-rate-limiter",[295],"trypema"," behind a feature flag, since the same platform that needed counting also needed rate limiting, and the two tend to show up together.",[25,328],{"className":329},[45],[21,331,332,333,253,335,337],{},"The API stays out of your way. You build the options once, then call ",[62,334,93],{},[62,336,175],{},", and friends. Here is the setup every example shares:",[25,339],{"className":340},[45],[342,343,348],"pre",{"className":344,"code":345,"language":346,"meta":347,"style":347},"language-rust shiki shiki-themes github-dark","use distkit::{DistkitRedisKey, counter::{StrictCounter, LaxCounter, CounterOptions, CounterTrait}};\n\nlet client = redis::Client::open(\"redis://127.0.0.1/\")?;\nlet conn = client.get_connection_manager().await?;\n\nlet prefix = DistkitRedisKey::try_from(\"my_app\".to_string())?;\nlet options = CounterOptions::new(prefix, conn);\nlet key = DistkitRedisKey::try_from(\"page_views\".to_string())?;\n","rust","",[62,349,350,401,408,449,475,480,515,536],{"__ignoreMap":347},[351,352,355,359,363,366,370,373,375,378,380,382,384,386,388,390,393,395,398],"span",{"class":353,"line":354},"line",1,[351,356,358],{"class":357},"snl16","use",[351,360,362],{"class":361},"svObZ"," distkit",[351,364,365],{"class":357},"::",[351,367,369],{"class":368},"s95oV","{",[351,371,372],{"class":361},"DistkitRedisKey",[351,374,253],{"class":368},[351,376,377],{"class":361},"counter",[351,379,365],{"class":357},[351,381,369],{"class":368},[351,383,306],{"class":361},[351,385,253],{"class":368},[351,387,309],{"class":361},[351,389,253],{"class":368},[351,391,392],{"class":361},"CounterOptions",[351,394,253],{"class":368},[351,396,397],{"class":361},"CounterTrait",[351,399,400],{"class":368},"}};\n",[351,402,404],{"class":353,"line":403},2,[351,405,407],{"emptyLinePlaceholder":406},true,"\n",[351,409,411,414,417,420,423,425,428,430,433,436,440,443,446],{"class":353,"line":410},3,[351,412,413],{"class":357},"let",[351,415,416],{"class":368}," client ",[351,418,419],{"class":357},"=",[351,421,422],{"class":361}," redis",[351,424,365],{"class":357},[351,426,427],{"class":361},"Client",[351,429,365],{"class":357},[351,431,432],{"class":361},"open",[351,434,435],{"class":368},"(",[351,437,439],{"class":438},"sU2Wk","\"redis://127.0.0.1/\"",[351,441,442],{"class":368},")",[351,444,445],{"class":357},"?",[351,447,448],{"class":368},";\n",[351,450,452,454,457,459,462,464,467,470,473],{"class":353,"line":451},4,[351,453,413],{"class":357},[351,455,456],{"class":368}," conn ",[351,458,419],{"class":357},[351,460,461],{"class":368}," client",[351,463,297],{"class":357},[351,465,466],{"class":361},"get_connection_manager",[351,468,469],{"class":368},"()",[351,471,472],{"class":357},".await?",[351,474,448],{"class":368},[351,476,478],{"class":353,"line":477},5,[351,479,407],{"emptyLinePlaceholder":406},[351,481,483,485,488,490,493,495,498,500,503,505,508,511,513],{"class":353,"line":482},6,[351,484,413],{"class":357},[351,486,487],{"class":368}," prefix ",[351,489,419],{"class":357},[351,491,492],{"class":361}," DistkitRedisKey",[351,494,365],{"class":357},[351,496,497],{"class":361},"try_from",[351,499,435],{"class":368},[351,501,502],{"class":438},"\"my_app\"",[351,504,297],{"class":357},[351,506,507],{"class":361},"to_string",[351,509,510],{"class":368},"())",[351,512,445],{"class":357},[351,514,448],{"class":368},[351,516,518,520,523,525,528,530,533],{"class":353,"line":517},7,[351,519,413],{"class":357},[351,521,522],{"class":368}," options ",[351,524,419],{"class":357},[351,526,527],{"class":361}," CounterOptions",[351,529,365],{"class":357},[351,531,532],{"class":361},"new",[351,534,535],{"class":368},"(prefix, conn);\n",[351,537,539,541,544,546,548,550,552,554,557,559,561,563,565],{"class":353,"line":538},8,[351,540,413],{"class":357},[351,542,543],{"class":368}," key ",[351,545,419],{"class":357},[351,547,492],{"class":361},[351,549,365],{"class":357},[351,551,497],{"class":361},[351,553,435],{"class":368},[351,555,556],{"class":438},"\"page_views\"",[351,558,297],{"class":357},[351,560,507],{"class":361},[351,562,510],{"class":368},[351,564,445],{"class":357},[351,566,448],{"class":368},[25,568],{"className":569},[45],[21,571,572],{},"A strict counter, where every read reflects the latest write:",[25,574],{"className":575},[45],[342,577,579],{"className":344,"code":578,"language":346,"meta":347,"style":347},"let counter = StrictCounter::new(options.clone());\n\ncounter.inc(&key, 1).await?;\nlet total = counter.get(&key).await?; // hits Redis, always exact\n",[62,580,581,608,612,638],{"__ignoreMap":347},[351,582,583,585,588,590,593,595,597,600,602,605],{"class":353,"line":354},[351,584,413],{"class":357},[351,586,587],{"class":368}," counter ",[351,589,419],{"class":357},[351,591,592],{"class":361}," StrictCounter",[351,594,365],{"class":357},[351,596,532],{"class":361},[351,598,599],{"class":368},"(options",[351,601,297],{"class":357},[351,603,604],{"class":361},"clone",[351,606,607],{"class":368},"());\n",[351,609,610],{"class":353,"line":403},[351,611,407],{"emptyLinePlaceholder":406},[351,613,614,616,618,620,622,625,628,632,634,636],{"class":353,"line":410},[351,615,377],{"class":368},[351,617,297],{"class":357},[351,619,93],{"class":361},[351,621,435],{"class":368},[351,623,624],{"class":357},"&",[351,626,627],{"class":368},"key, ",[351,629,631],{"class":630},"sDLfK","1",[351,633,442],{"class":368},[351,635,472],{"class":357},[351,637,448],{"class":368},[351,639,640,642,645,647,650,652,654,656,658,661,663,666],{"class":353,"line":451},[351,641,413],{"class":357},[351,643,644],{"class":368}," total ",[351,646,419],{"class":357},[351,648,649],{"class":368}," counter",[351,651,297],{"class":357},[351,653,175],{"class":361},[351,655,435],{"class":368},[351,657,624],{"class":357},[351,659,660],{"class":368},"key)",[351,662,472],{"class":357},[351,664,665],{"class":368},"; ",[351,667,669],{"class":668},"sAwPA","// hits Redis, always exact\n",[25,671],{"className":672},[45],[21,674,675],{},"A lax counter, where increments stay in memory and flush on an interval:",[25,677],{"className":678},[45],[342,680,682],{"className":344,"code":681,"language":346,"meta":347,"style":347},"let counter = LaxCounter::new(options);\n\ncounter.inc(&key, 1).await?;          // local, returns immediately\nlet total = counter.get(&key).await?; // local view, no Redis hit\n",[62,683,684,702,706,732],{"__ignoreMap":347},[351,685,686,688,690,692,695,697,699],{"class":353,"line":354},[351,687,413],{"class":357},[351,689,587],{"class":368},[351,691,419],{"class":357},[351,693,694],{"class":361}," LaxCounter",[351,696,365],{"class":357},[351,698,532],{"class":361},[351,700,701],{"class":368},"(options);\n",[351,703,704],{"class":353,"line":403},[351,705,407],{"emptyLinePlaceholder":406},[351,707,708,710,712,714,716,718,720,722,724,726,729],{"class":353,"line":410},[351,709,377],{"class":368},[351,711,297],{"class":357},[351,713,93],{"class":361},[351,715,435],{"class":368},[351,717,624],{"class":357},[351,719,627],{"class":368},[351,721,631],{"class":630},[351,723,442],{"class":368},[351,725,472],{"class":357},[351,727,728],{"class":368},";          ",[351,730,731],{"class":668},"// local, returns immediately\n",[351,733,734,736,738,740,742,744,746,748,750,752,754,756],{"class":353,"line":451},[351,735,413],{"class":357},[351,737,644],{"class":368},[351,739,419],{"class":357},[351,741,649],{"class":368},[351,743,297],{"class":357},[351,745,175],{"class":361},[351,747,435],{"class":368},[351,749,624],{"class":357},[351,751,660],{"class":368},[351,753,472],{"class":357},[351,755,665],{"class":368},[351,757,758],{"class":668},"// local view, no Redis hit\n",[25,760],{"className":761},[45],[21,763,764],{},"And an instance aware counter, where every call hands back both the cluster total and this instance's own slice:",[25,766],{"className":767},[45],[342,769,771],{"className":344,"code":770,"language":346,"meta":347,"style":347},"use distkit::icounter::{\n    InstanceAwareCounterTrait,\n    StrictInstanceAwareCounter, StrictInstanceAwareCounterOptions,\n};\n\nlet counter = StrictInstanceAwareCounter::new(\n    StrictInstanceAwareCounterOptions::new(prefix, conn),\n);\n\nlet (total, mine) = counter.inc(&key, 1).await?;\nlet (total, mine) = counter.dec(&key, 1).await?;\n",[62,772,773,789,797,809,814,818,836,848,853,858,888],{"__ignoreMap":347},[351,774,775,777,779,781,784,786],{"class":353,"line":354},[351,776,358],{"class":357},[351,778,362],{"class":361},[351,780,365],{"class":357},[351,782,783],{"class":361},"icounter",[351,785,365],{"class":357},[351,787,788],{"class":368},"{\n",[351,790,791,794],{"class":353,"line":403},[351,792,793],{"class":361},"    InstanceAwareCounterTrait",[351,795,796],{"class":368},",\n",[351,798,799,802,804,807],{"class":353,"line":410},[351,800,801],{"class":361},"    StrictInstanceAwareCounter",[351,803,253],{"class":368},[351,805,806],{"class":361},"StrictInstanceAwareCounterOptions",[351,808,796],{"class":368},[351,810,811],{"class":353,"line":451},[351,812,813],{"class":368},"};\n",[351,815,816],{"class":353,"line":477},[351,817,407],{"emptyLinePlaceholder":406},[351,819,820,822,824,826,829,831,833],{"class":353,"line":482},[351,821,413],{"class":357},[351,823,587],{"class":368},[351,825,419],{"class":357},[351,827,828],{"class":361}," StrictInstanceAwareCounter",[351,830,365],{"class":357},[351,832,532],{"class":361},[351,834,835],{"class":368},"(\n",[351,837,838,841,843,845],{"class":353,"line":517},[351,839,840],{"class":361},"    StrictInstanceAwareCounterOptions",[351,842,365],{"class":357},[351,844,532],{"class":361},[351,846,847],{"class":368},"(prefix, conn),\n",[351,849,850],{"class":353,"line":538},[351,851,852],{"class":368},");\n",[351,854,856],{"class":353,"line":855},9,[351,857,407],{"emptyLinePlaceholder":406},[351,859,861,863,866,868,870,872,874,876,878,880,882,884,886],{"class":353,"line":860},10,[351,862,413],{"class":357},[351,864,865],{"class":368}," (total, mine) ",[351,867,419],{"class":357},[351,869,649],{"class":368},[351,871,297],{"class":357},[351,873,93],{"class":361},[351,875,435],{"class":368},[351,877,624],{"class":357},[351,879,627],{"class":368},[351,881,631],{"class":630},[351,883,442],{"class":368},[351,885,472],{"class":357},[351,887,448],{"class":368},[351,889,891,893,895,897,899,901,903,905,907,909,911,913,915],{"class":353,"line":890},11,[351,892,413],{"class":357},[351,894,865],{"class":368},[351,896,419],{"class":357},[351,898,649],{"class":368},[351,900,297],{"class":357},[351,902,243],{"class":361},[351,904,435],{"class":368},[351,906,624],{"class":357},[351,908,627],{"class":368},[351,910,631],{"class":630},[351,912,442],{"class":368},[351,914,472],{"class":357},[351,916,448],{"class":368},[25,918],{"className":919},[45],[21,921,922,923,297],{},"If you have a similar problem and you would rather not reimplement any of the above, ",[291,924,927],{"href":925,"rel":926},"https://crates.io/crates/distkit",[295],"the crate is on crates.io",[25,929],{"className":930},[36],[932,933],"hr",{},[25,935],{"className":936},[36],[938,939,940],"style",{},"html pre.shiki code .snl16, html code.shiki .snl16{--shiki-default:#F97583}html pre.shiki code .svObZ, html code.shiki .svObZ{--shiki-default:#B392F0}html pre.shiki code .s95oV, html code.shiki .s95oV{--shiki-default:#E1E4E8}html pre.shiki code .sU2Wk, html code.shiki .sU2Wk{--shiki-default:#9ECBFF}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 .sDLfK, html code.shiki .sDLfK{--shiki-default:#79B8FF}html pre.shiki code .sAwPA, html code.shiki .sAwPA{--shiki-default:#6A737D}",{"title":347,"searchDepth":403,"depth":403,"links":942},[943,944,945,946,947,948,949,950],{"id":40,"depth":403,"text":41},{"id":77,"depth":403,"text":78},{"id":106,"depth":403,"text":107},{"id":131,"depth":403,"text":132},{"id":156,"depth":403,"text":157},{"id":198,"depth":403,"text":199},{"id":231,"depth":403,"text":232},{"id":282,"depth":403,"text":283},"2026-06-14T00:00:00.000Z","Counting things across multiple servers sounds trivial. It is not. A walkthrough of the design space for distributed counters, from atomic Redis scripts to per instance tracking with automatic cleanup of dead instances, and the Rust crate I built to handle all of it.","md","/projects/distkit/main.png",{},"https://davidoyinbo.com/engineering-logs/distributed-counters","/engineering-logs/distributed-counters","8 min",{"title":5,"description":952},"engineering-logs/distributed-counters",[346,962,963,964,965],"distributed-systems","redis","engineering","counters","OqycKN1ixWTmuncJ4YUqIB6GmuXsvcmDuOG4wfdvb0E",[968,1106,4033],{"id":969,"title":970,"author":6,"body":971,"date":1091,"description":982,"extension":953,"image_url":1092,"meta":1093,"navigation":406,"original_url":1094,"path":1095,"readTime":1096,"seo":1097,"stem":1098,"tags":1099,"__hash__":1105},"engineeringLogs/engineering-logs/break-tutorial-trap.md","Break the Tutorial Trap: How to Become a Better Software Engineer with Projects & Structure",{"type":8,"value":972,"toc":1089},[973,977,980,983,986,989,992,995,998,1009,1012,1021,1024,1027,1030,1033,1043,1046,1061,1069,1073,1076,1080],[11,974],{"className":975,"date":976},[14],"2024-04-15",[17,978,970],{"id":979},"break-the-tutorial-trap-how-to-become-a-better-software-engineer-with-projects-structure",[21,981,982],{},"Practical advice for moving beyond tutorial-following by building structured projects that teach real engineering skills.",[25,984],{"className":985},[28],[30,987],{":tags":988},"[\"Learning\", \"Tutorials\", \"Projects\", \"Software Engineering\", \"Career\"]",[25,990],{"className":991},[36],[21,993,994],{},"Becoming a software engineer is no trivial task. There are different hoops one has to go through, from learning basic computer science and learning about computer programming to designing a distributed system that would have to work across the world…(drifting off) yiddi yaddi yadda.",[25,996],{"className":997},[36],[999,1000],"iframe",{"width":1001,"height":1002,"src":1003,"title":1004,"frameBorder":1005,"className":1006,"allow":1008,"allowFullScreen":406},560,315,"https://www.youtube.com/embed/uzuV5KMbqbw","Break the Tutorial Trap: How to Become a Better Software Engineer","0",[1007],"max-w-full","accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture",[25,1010],{"className":1011},[36],[21,1013,1014,1015,1020],{},"Hands down, one of the easiest way to learn and gather information is through video tutorials given that books can easily become boring (even though I would actually suggest reading books). Which is why I also made a ",[291,1016,1019],{"href":1017,"rel":1018},"https://youtu.be/uzuV5KMbqbw",[295],"video version of this on youtube"," . The cons of tutorials are also its flaws, the main con is the fact that the tutorial focuses on a problem and gives you just the solution. But many of them would miss a crucial part, which is the process of getting to the solution. You see, the creators of tutorials would have gone through different problems and solutions before coming up with the perfect solution that they use for the tutorial, that process is exactly what you need to become a software engineer.",[25,1022],{"className":1023},[36],[21,1025,1026],{},"Software engineering is a craft, and the major way to grow is to go through the rigor of creating a solution, finding bugs, having sleepless nights because you forgot a semicolon or the fact that you forgot to free an allocated memory.",[25,1028],{"className":1029},[36],[21,1031,1032],{},"This process has to be guided also, which means you need a structure, this can be achieved by the following:",[1034,1035,1036,1040],"ul",{},[1037,1038,1039],"li",{},"Having a mentor",[1037,1041,1042],{},"Creating projects from begineer to advance",[25,1044],{"className":1045},[36],[21,1047,1048,1049,1054,1055,1060],{},"For mentors, you can join communities or send messages to individuals on linkedin. But I am here to talk about the structure for you. So I would suggest using tools like ",[291,1050,1053],{"href":1051,"rel":1052},"https://www.frontendmentor.io/",[295],"frontend mentor"," where you can find projects to work on, and it can help improve your portfolio. Most importantly, the software I would suggest is the community maintained ",[291,1056,1059],{"href":1057,"rel":1058},"https://roadmap.sh/",[295],"roadmap",". It contains career based roadmaps and skilled based roadmaps",[1062,1063],"content-image",{"alt":1064,"className":1065,"image":1068},"Roadmap",[1066,1067],"my-8","max-w-2xl","/engineering-logs/break-tutorial-trap/roadmap.webp",[1062,1070],{"alt":1064,"className":1071,"image":1072},[1066,1067],"/engineering-logs/break-tutorial-trap/roadmap-backend-2.webp",[21,1074,1075],{},"And for some of them (like this backend roadmap), projects are included, ranked from beginners to advance",[1062,1077],{"alt":1064,"className":1078,"image":1079},[1066,1067],"/engineering-logs/break-tutorial-trap/roadmap-backend-1.webp",[21,1081,1082,1083,1088],{},"I wish you good luck in your software engineering journey. I have created a ",[291,1084,1087],{"href":1085,"rel":1086},"https://www.youtube.com/@buildingblockdev?sub_confirmation=1",[295],"youtube channel"," dedicated to learning the building blocks of software engineering.",{"title":347,"searchDepth":403,"depth":403,"links":1090},[],"2024-04-15T00:00:00.000Z","/engineering-logs/break-tutorial-trap/main.webp",{},"https://medium.com/@dev.davexoyinbo/break-the-tutorial-trap-how-to-become-a-better-software-engineer-with-projects-structure-56b016505ed0","/engineering-logs/break-tutorial-trap","3 min",{"title":970,"description":982},"engineering-logs/break-tutorial-trap",[1100,1101,1102,1103,1104],"learning","tutorials","projects","software-engineering","career","oa-V5AOWSsHgDj32HDo9CXAvnGWg_GziXbsGyHaIEGo",{"id":1107,"title":1108,"author":6,"body":1109,"date":4019,"description":4020,"extension":953,"image_url":4021,"meta":4022,"navigation":406,"original_url":3997,"path":4023,"readTime":4024,"seo":4025,"stem":4026,"tags":4027,"__hash__":4032},"engineeringLogs/engineering-logs/embracing-perfection-rust.md","Embracing Perfection: A Journey into Rust Programming",{"type":8,"value":1110,"toc":4004},[1111,1115,1118,1121,1124,1127,1130,1134,1137,1140,1144,1147,1150,1155,1158,1162,1167,1170,1173,1179,1182,1298,1301,1311,1314,1318,1321,1324,1329,1332,1518,1521,1550,1553,1557,1560,1563,1567,1570,1573,1578,1581,1771,1774,1797,1800,1804,1807,1810,1815,1818,2130,2133,2163,2166,2170,2173,2176,2179,2184,2187,2309,2312,2322,2325,2330,2333,2462,2465,2478,2481,2484,2488,2491,2494,2499,2502,2695,2698,2709,2712,2717,2720,2819,2822,2836,2839,2842,2846,2849,2852,2857,2860,2966,2969,2989,2992,2997,3000,3225,3228,3262,3265,3270,3273,3386,3389,3415,3418,3421,3425,3428,3431,3434,3439,3442,3527,3530,3558,3561,3564,3578,3581,3585,3588,3591,3595,3598,3603,3606,3918,3921,3933,3953,3959,3965,3968,3972,3975,3978,3981,3984,3986,3989,4001],[11,1112],{"className":1113,"date":1114},[14],"2023-06-20",[17,1116,1108],{"id":1117},"embracing-perfection-a-journey-into-rust-programming",[21,1119,1120],{},"Embarking on the journey of learning Rust is like stepping into a world that demands perfection. While it may not be the easiest language to master, Rust offers a unique set of features and concepts that push developers to consider every aspect of their code.",[25,1122],{"className":1123},[28],[30,1125],{":tags":1126},"[\"Rust\", \"Programming\", \"Backend\", \"Systems\", \"Memory Safety\"]",[25,1128],{"className":1129},[36],[38,1131,1133],{"id":1132},"overview","Overview",[21,1135,1136],{},"In this article, we will explore some of the core features and concepts that make Rust a powerful and compelling language for developers. Whether you're a beginner or an experienced programmer, these insights will help you understand and appreciate the value of Rust's ownership system, pattern matching, lifetimes, and concurrency primitives.",[25,1138],{"className":1139},[36],[38,1141,1143],{"id":1142},"_1-embracing-functional-and-object-oriented-concepts-in-rust","1. Embracing Functional and Object-Oriented Concepts in Rust",[21,1145,1146],{},"Rust is a versatile language that combines elements of functional programming and object-oriented programming (OOP) paradigms. While it is not a strictly functional or purely OOP language, Rust provides powerful features and concepts that allow developers to embrace functional and OOP principles in their code. Let's explore how Rust handles these concepts and empowers developers to write expressive and modular code.",[25,1148],{"className":1149},[36],[1151,1152,1154],"h3",{"id":1153},"functional-programming-in-rust","Functional Programming in Rust",[21,1156,1157],{},"Functional programming emphasizes immutability, pure functions, and higher-order functions. Although Rust is not a pure functional language, it offers several features that align with functional programming principles.",[25,1159],{"className":1160},[1161],"mb-6",[1163,1164,1166],"h4",{"id":1165},"immutability-and-functional-concepts","Immutability and Functional Concepts",[21,1168,1169],{},"Rust encourages immutability by default. Variables are immutable by default, and you need to explicitly mark them as mutable when necessary. This approach aligns with functional programming's emphasis on immutability to avoid unintended side effects and improve code clarity.",[25,1171],{"className":1172},[36],[21,1174,1175],{},[1176,1177,1178],"strong",{},"Example: Immutability in Rust",[25,1180],{"className":1181},[45],[342,1183,1186],{"className":344,"code":1184,"filename":1185,"language":346,"meta":347,"style":347},"fn main() {\n    let x = 5; // Immutable binding\n    let y = {\n        let x = 2; // Shadowing with new binding\n        x + 1\n    };\n    println!(\"x: {}\", x); // Prints 5\n    println!(\"y: {}\", y); // Prints 3\n}\n","main.rs",[62,1187,1188,1199,1217,1229,1246,1257,1262,1278,1293],{"__ignoreMap":347},[351,1189,1190,1193,1196],{"class":353,"line":354},[351,1191,1192],{"class":357},"fn",[351,1194,1195],{"class":361}," main",[351,1197,1198],{"class":368},"() {\n",[351,1200,1201,1204,1207,1209,1212,1214],{"class":353,"line":403},[351,1202,1203],{"class":357},"    let",[351,1205,1206],{"class":368}," x ",[351,1208,419],{"class":357},[351,1210,1211],{"class":630}," 5",[351,1213,665],{"class":368},[351,1215,1216],{"class":668},"// Immutable binding\n",[351,1218,1219,1221,1224,1226],{"class":353,"line":410},[351,1220,1203],{"class":357},[351,1222,1223],{"class":368}," y ",[351,1225,419],{"class":357},[351,1227,1228],{"class":368}," {\n",[351,1230,1231,1234,1236,1238,1241,1243],{"class":353,"line":451},[351,1232,1233],{"class":357},"        let",[351,1235,1206],{"class":368},[351,1237,419],{"class":357},[351,1239,1240],{"class":630}," 2",[351,1242,665],{"class":368},[351,1244,1245],{"class":668},"// Shadowing with new binding\n",[351,1247,1248,1251,1254],{"class":353,"line":477},[351,1249,1250],{"class":368},"        x ",[351,1252,1253],{"class":357},"+",[351,1255,1256],{"class":630}," 1\n",[351,1258,1259],{"class":353,"line":482},[351,1260,1261],{"class":368},"    };\n",[351,1263,1264,1267,1269,1272,1275],{"class":353,"line":517},[351,1265,1266],{"class":361},"    println!",[351,1268,435],{"class":368},[351,1270,1271],{"class":438},"\"x: {}\"",[351,1273,1274],{"class":368},", x); ",[351,1276,1277],{"class":668},"// Prints 5\n",[351,1279,1280,1282,1284,1287,1290],{"class":353,"line":538},[351,1281,1266],{"class":361},[351,1283,435],{"class":368},[351,1285,1286],{"class":438},"\"y: {}\"",[351,1288,1289],{"class":368},", y); ",[351,1291,1292],{"class":668},"// Prints 3\n",[351,1294,1295],{"class":353,"line":855},[351,1296,1297],{"class":368},"}\n",[25,1299],{"className":1300},[45],[21,1302,1303,1304,1307,1308,1310],{},"In this example, the variable ",[62,1305,1306],{},"x"," is initially bound to the value 5. Inside the block, we create a new binding, also named ",[62,1309,1306],{},", which shadows the outer binding. This demonstrates Rust's support for functional-style immutability through shadowing.",[25,1312],{"className":1313},[1161],[1163,1315,1317],{"id":1316},"higher-order-functions","Higher-Order Functions",[21,1319,1320],{},"Rust supports higher-order functions, allowing you to pass functions as arguments or return them from other functions. This enables powerful abstractions and functional composition.",[25,1322],{"className":1323},[36],[21,1325,1326],{},[1176,1327,1328],{},"Example: Higher-Order Functions in Rust",[25,1330],{"className":1331},[45],[342,1333,1335],{"className":344,"code":1334,"filename":1185,"language":346,"meta":347,"style":347},"fn apply_twice\u003CF>(f: F, x: i32) -> i32\nwhere\n    F: Fn(i32) -> i32,\n{\n    f(f(x))\n}\n\nfn add_one(x: i32) -> i32 {\n    x + 1\n}\n\nfn main() {\n    let result = apply_twice(add_one, 2);\n    println!(\"Result: {}\", result); // Prints 4\n}\n",[62,1336,1337,1376,1381,1404,1408,1421,1425,1429,1451,1460,1464,1468,1477,1497,1513],{"__ignoreMap":347},[351,1338,1339,1341,1344,1347,1350,1353,1356,1359,1362,1364,1367,1370,1373],{"class":353,"line":354},[351,1340,1192],{"class":357},[351,1342,1343],{"class":361}," apply_twice",[351,1345,1346],{"class":368},"\u003C",[351,1348,1349],{"class":361},"F",[351,1351,1352],{"class":368},">(f",[351,1354,1355],{"class":357},":",[351,1357,1358],{"class":361}," F",[351,1360,1361],{"class":368},", x",[351,1363,1355],{"class":357},[351,1365,1366],{"class":361}," i32",[351,1368,1369],{"class":368},") ",[351,1371,1372],{"class":357},"->",[351,1374,1375],{"class":361}," i32\n",[351,1377,1378],{"class":353,"line":403},[351,1379,1380],{"class":357},"where\n",[351,1382,1383,1386,1388,1391,1393,1396,1398,1400,1402],{"class":353,"line":410},[351,1384,1385],{"class":361},"    F",[351,1387,1355],{"class":357},[351,1389,1390],{"class":361}," Fn",[351,1392,435],{"class":368},[351,1394,1395],{"class":361},"i32",[351,1397,1369],{"class":368},[351,1399,1372],{"class":357},[351,1401,1366],{"class":361},[351,1403,796],{"class":368},[351,1405,1406],{"class":353,"line":451},[351,1407,788],{"class":368},[351,1409,1410,1413,1415,1418],{"class":353,"line":477},[351,1411,1412],{"class":361},"    f",[351,1414,435],{"class":368},[351,1416,1417],{"class":361},"f",[351,1419,1420],{"class":368},"(x))\n",[351,1422,1423],{"class":353,"line":482},[351,1424,1297],{"class":368},[351,1426,1427],{"class":353,"line":517},[351,1428,407],{"emptyLinePlaceholder":406},[351,1430,1431,1433,1436,1439,1441,1443,1445,1447,1449],{"class":353,"line":538},[351,1432,1192],{"class":357},[351,1434,1435],{"class":361}," add_one",[351,1437,1438],{"class":368},"(x",[351,1440,1355],{"class":357},[351,1442,1366],{"class":361},[351,1444,1369],{"class":368},[351,1446,1372],{"class":357},[351,1448,1366],{"class":361},[351,1450,1228],{"class":368},[351,1452,1453,1456,1458],{"class":353,"line":855},[351,1454,1455],{"class":368},"    x ",[351,1457,1253],{"class":357},[351,1459,1256],{"class":630},[351,1461,1462],{"class":353,"line":860},[351,1463,1297],{"class":368},[351,1465,1466],{"class":353,"line":890},[351,1467,407],{"emptyLinePlaceholder":406},[351,1469,1471,1473,1475],{"class":353,"line":1470},12,[351,1472,1192],{"class":357},[351,1474,1195],{"class":361},[351,1476,1198],{"class":368},[351,1478,1480,1482,1485,1487,1489,1492,1495],{"class":353,"line":1479},13,[351,1481,1203],{"class":357},[351,1483,1484],{"class":368}," result ",[351,1486,419],{"class":357},[351,1488,1343],{"class":361},[351,1490,1491],{"class":368},"(add_one, ",[351,1493,1494],{"class":630},"2",[351,1496,852],{"class":368},[351,1498,1500,1502,1504,1507,1510],{"class":353,"line":1499},14,[351,1501,1266],{"class":361},[351,1503,435],{"class":368},[351,1505,1506],{"class":438},"\"Result: {}\"",[351,1508,1509],{"class":368},", result); ",[351,1511,1512],{"class":668},"// Prints 4\n",[351,1514,1516],{"class":353,"line":1515},15,[351,1517,1297],{"class":368},[25,1519],{"className":1520},[45],[21,1522,1523,1524,1527,1528,1530,1531,1533,1534,1536,1537,1539,1540,1542,1543,1546,1547,1549],{},"In this example, the ",[62,1525,1526],{},"apply_twice"," function takes a closure ",[62,1529,1417],{}," and applies it twice to the argument ",[62,1532,1306],{},". The closure ",[62,1535,1349],{}," is a higher-order function that takes an ",[62,1538,1395],{}," argument and returns an ",[62,1541,1395],{},". We pass the ",[62,1544,1545],{},"add_one"," function as an argument to ",[62,1548,1526],{},", demonstrating the ability to pass functions as arguments and apply them within Rust.",[25,1551],{"className":1552},[1161],[1151,1554,1556],{"id":1555},"object-oriented-programming-in-rust","Object-Oriented Programming in Rust",[21,1558,1559],{},"While Rust does not have traditional class-based OOP like languages such as Java or C++, it provides features that allow developers to achieve object-oriented designs and encapsulation.",[25,1561],{"className":1562},[1161],[1163,1564,1566],{"id":1565},"structs-and-methods","Structs and Methods",[21,1568,1569],{},"Rust uses structs to define custom data types and associated methods. Methods are functions defined within the context of a struct, enabling data encapsulation and object-like behavior.",[25,1571],{"className":1572},[36],[21,1574,1575],{},[1176,1576,1577],{},"Example: Structs and Methods in Rust",[25,1579],{"className":1580},[45],[342,1582,1584],{"className":344,"code":1583,"filename":1185,"language":346,"meta":347,"style":347},"struct Rectangle {\n    width: u32,\n    height: u32,\n}\n\nimpl Rectangle {\n    fn area(&self) -> u32 {\n        self.width * self.height\n    }\n}\n\nfn main() {\n    let rect = Rectangle {\n        width: 10,\n        height: 5,\n    };\n    println!(\"Area: {}\", rect.area()); // Prints 50\n}\n",[62,1585,1586,1596,1608,1619,1623,1627,1636,1659,1680,1685,1689,1693,1701,1714,1726,1737,1742,1766],{"__ignoreMap":347},[351,1587,1588,1591,1594],{"class":353,"line":354},[351,1589,1590],{"class":357},"struct",[351,1592,1593],{"class":361}," Rectangle",[351,1595,1228],{"class":368},[351,1597,1598,1601,1603,1606],{"class":353,"line":403},[351,1599,1600],{"class":368},"    width",[351,1602,1355],{"class":357},[351,1604,1605],{"class":361}," u32",[351,1607,796],{"class":368},[351,1609,1610,1613,1615,1617],{"class":353,"line":410},[351,1611,1612],{"class":368},"    height",[351,1614,1355],{"class":357},[351,1616,1605],{"class":361},[351,1618,796],{"class":368},[351,1620,1621],{"class":353,"line":451},[351,1622,1297],{"class":368},[351,1624,1625],{"class":353,"line":477},[351,1626,407],{"emptyLinePlaceholder":406},[351,1628,1629,1632,1634],{"class":353,"line":482},[351,1630,1631],{"class":357},"impl",[351,1633,1593],{"class":361},[351,1635,1228],{"class":368},[351,1637,1638,1641,1644,1646,1648,1651,1653,1655,1657],{"class":353,"line":517},[351,1639,1640],{"class":357},"    fn",[351,1642,1643],{"class":361}," area",[351,1645,435],{"class":368},[351,1647,624],{"class":357},[351,1649,1650],{"class":630},"self",[351,1652,1369],{"class":368},[351,1654,1372],{"class":357},[351,1656,1605],{"class":361},[351,1658,1228],{"class":368},[351,1660,1661,1664,1666,1669,1672,1675,1677],{"class":353,"line":538},[351,1662,1663],{"class":630},"        self",[351,1665,297],{"class":357},[351,1667,1668],{"class":368},"width ",[351,1670,1671],{"class":357},"*",[351,1673,1674],{"class":630}," self",[351,1676,297],{"class":357},[351,1678,1679],{"class":368},"height\n",[351,1681,1682],{"class":353,"line":855},[351,1683,1684],{"class":368},"    }\n",[351,1686,1687],{"class":353,"line":860},[351,1688,1297],{"class":368},[351,1690,1691],{"class":353,"line":890},[351,1692,407],{"emptyLinePlaceholder":406},[351,1694,1695,1697,1699],{"class":353,"line":1470},[351,1696,1192],{"class":357},[351,1698,1195],{"class":361},[351,1700,1198],{"class":368},[351,1702,1703,1705,1708,1710,1712],{"class":353,"line":1479},[351,1704,1203],{"class":357},[351,1706,1707],{"class":368}," rect ",[351,1709,419],{"class":357},[351,1711,1593],{"class":361},[351,1713,1228],{"class":368},[351,1715,1716,1719,1721,1724],{"class":353,"line":1499},[351,1717,1718],{"class":368},"        width",[351,1720,1355],{"class":357},[351,1722,1723],{"class":630}," 10",[351,1725,796],{"class":368},[351,1727,1728,1731,1733,1735],{"class":353,"line":1515},[351,1729,1730],{"class":368},"        height",[351,1732,1355],{"class":357},[351,1734,1211],{"class":630},[351,1736,796],{"class":368},[351,1738,1740],{"class":353,"line":1739},16,[351,1741,1261],{"class":368},[351,1743,1745,1747,1749,1752,1755,1757,1760,1763],{"class":353,"line":1744},17,[351,1746,1266],{"class":361},[351,1748,435],{"class":368},[351,1750,1751],{"class":438},"\"Area: {}\"",[351,1753,1754],{"class":368},", rect",[351,1756,297],{"class":357},[351,1758,1759],{"class":361},"area",[351,1761,1762],{"class":368},"()); ",[351,1764,1765],{"class":668},"// Prints 50\n",[351,1767,1769],{"class":353,"line":1768},18,[351,1770,1297],{"class":368},[25,1772],{"className":1773},[45],[21,1775,1776,1777,1780,1781,215,1784,1787,1788,1790,1791,1793,1794,1796],{},"In this example, we define a ",[62,1778,1779],{},"Rectangle"," struct with ",[62,1782,1783],{},"width",[62,1785,1786],{},"height"," fields. We implement an associated method ",[62,1789,1759],{}," for the struct, which calculates and returns the area of the rectangle. By using the ",[62,1792,1631],{}," block, we define the implementation of the methods associated with the ",[62,1795,1779],{}," struct.",[25,1798],{"className":1799},[1161],[1163,1801,1803],{"id":1802},"traits-and-polymorphism","Traits and Polymorphism",[21,1805,1806],{},"Rust's trait system provides a way to achieve polymorphism and code reuse, similar to interfaces in OOP languages. Traits define behavior that types can implement, allowing for dynamic dispatch and runtime polymorphism.",[25,1808],{"className":1809},[36],[21,1811,1812],{},[1176,1813,1814],{},"Example: Traits and Polymorphism in Rust",[25,1816],{"className":1817},[45],[342,1819,1821],{"className":344,"code":1820,"filename":1185,"language":346,"meta":347,"style":347},"trait Animal {\n    fn sound(&self);\n}\n\nstruct Dog;\nstruct Cat;\n\nimpl Animal for Dog {\n    fn sound(&self) {\n        println!(\"Woof!\");\n    }\n}\n\nimpl Animal for Cat {\n    fn sound(&self) {\n        println!(\"Meow!\");\n    }\n}\n\nfn main() {\n    let dog: Dog = Dog;\n    let cat: Cat = Cat;\n    \n    let animals: Vec\u003CBox\u003Cdyn Animal>> = vec![Box::new(dog), Box::new(cat)];\n    \n    for animal in animals {\n        animal.sound();\n    }\n}\n",[62,1822,1823,1833,1848,1852,1856,1865,1874,1878,1891,1906,1918,1922,1926,1930,1942,1956,1967,1971,1975,1980,1989,2008,2026,2032,2086,2091,2106,2120,2125],{"__ignoreMap":347},[351,1824,1825,1828,1831],{"class":353,"line":354},[351,1826,1827],{"class":357},"trait",[351,1829,1830],{"class":361}," Animal",[351,1832,1228],{"class":368},[351,1834,1835,1837,1840,1842,1844,1846],{"class":353,"line":403},[351,1836,1640],{"class":357},[351,1838,1839],{"class":361}," sound",[351,1841,435],{"class":368},[351,1843,624],{"class":357},[351,1845,1650],{"class":630},[351,1847,852],{"class":368},[351,1849,1850],{"class":353,"line":410},[351,1851,1297],{"class":368},[351,1853,1854],{"class":353,"line":451},[351,1855,407],{"emptyLinePlaceholder":406},[351,1857,1858,1860,1863],{"class":353,"line":477},[351,1859,1590],{"class":357},[351,1861,1862],{"class":361}," Dog",[351,1864,448],{"class":368},[351,1866,1867,1869,1872],{"class":353,"line":482},[351,1868,1590],{"class":357},[351,1870,1871],{"class":361}," Cat",[351,1873,448],{"class":368},[351,1875,1876],{"class":353,"line":517},[351,1877,407],{"emptyLinePlaceholder":406},[351,1879,1880,1882,1884,1887,1889],{"class":353,"line":538},[351,1881,1631],{"class":357},[351,1883,1830],{"class":361},[351,1885,1886],{"class":357}," for",[351,1888,1862],{"class":361},[351,1890,1228],{"class":368},[351,1892,1893,1895,1897,1899,1901,1903],{"class":353,"line":855},[351,1894,1640],{"class":357},[351,1896,1839],{"class":361},[351,1898,435],{"class":368},[351,1900,624],{"class":357},[351,1902,1650],{"class":630},[351,1904,1905],{"class":368},") {\n",[351,1907,1908,1911,1913,1916],{"class":353,"line":860},[351,1909,1910],{"class":361},"        println!",[351,1912,435],{"class":368},[351,1914,1915],{"class":438},"\"Woof!\"",[351,1917,852],{"class":368},[351,1919,1920],{"class":353,"line":890},[351,1921,1684],{"class":368},[351,1923,1924],{"class":353,"line":1470},[351,1925,1297],{"class":368},[351,1927,1928],{"class":353,"line":1479},[351,1929,407],{"emptyLinePlaceholder":406},[351,1931,1932,1934,1936,1938,1940],{"class":353,"line":1499},[351,1933,1631],{"class":357},[351,1935,1830],{"class":361},[351,1937,1886],{"class":357},[351,1939,1871],{"class":361},[351,1941,1228],{"class":368},[351,1943,1944,1946,1948,1950,1952,1954],{"class":353,"line":1515},[351,1945,1640],{"class":357},[351,1947,1839],{"class":361},[351,1949,435],{"class":368},[351,1951,624],{"class":357},[351,1953,1650],{"class":630},[351,1955,1905],{"class":368},[351,1957,1958,1960,1962,1965],{"class":353,"line":1739},[351,1959,1910],{"class":361},[351,1961,435],{"class":368},[351,1963,1964],{"class":438},"\"Meow!\"",[351,1966,852],{"class":368},[351,1968,1969],{"class":353,"line":1744},[351,1970,1684],{"class":368},[351,1972,1973],{"class":353,"line":1768},[351,1974,1297],{"class":368},[351,1976,1978],{"class":353,"line":1977},19,[351,1979,407],{"emptyLinePlaceholder":406},[351,1981,1983,1985,1987],{"class":353,"line":1982},20,[351,1984,1192],{"class":357},[351,1986,1195],{"class":361},[351,1988,1198],{"class":368},[351,1990,1992,1994,1997,1999,2001,2004,2006],{"class":353,"line":1991},21,[351,1993,1203],{"class":357},[351,1995,1996],{"class":368}," dog",[351,1998,1355],{"class":357},[351,2000,1862],{"class":361},[351,2002,2003],{"class":357}," =",[351,2005,1862],{"class":361},[351,2007,448],{"class":368},[351,2009,2011,2013,2016,2018,2020,2022,2024],{"class":353,"line":2010},22,[351,2012,1203],{"class":357},[351,2014,2015],{"class":368}," cat",[351,2017,1355],{"class":357},[351,2019,1871],{"class":361},[351,2021,2003],{"class":357},[351,2023,1871],{"class":361},[351,2025,448],{"class":368},[351,2027,2029],{"class":353,"line":2028},23,[351,2030,2031],{"class":368},"    \n",[351,2033,2035,2037,2040,2042,2045,2047,2050,2052,2055,2057,2060,2062,2065,2068,2070,2072,2074,2077,2079,2081,2083],{"class":353,"line":2034},24,[351,2036,1203],{"class":357},[351,2038,2039],{"class":368}," animals",[351,2041,1355],{"class":357},[351,2043,2044],{"class":361}," Vec",[351,2046,1346],{"class":368},[351,2048,2049],{"class":361},"Box",[351,2051,1346],{"class":368},[351,2053,2054],{"class":357},"dyn",[351,2056,1830],{"class":361},[351,2058,2059],{"class":368},">> ",[351,2061,419],{"class":357},[351,2063,2064],{"class":361}," vec!",[351,2066,2067],{"class":368},"[",[351,2069,2049],{"class":361},[351,2071,365],{"class":357},[351,2073,532],{"class":361},[351,2075,2076],{"class":368},"(dog), ",[351,2078,2049],{"class":361},[351,2080,365],{"class":357},[351,2082,532],{"class":361},[351,2084,2085],{"class":368},"(cat)];\n",[351,2087,2089],{"class":353,"line":2088},25,[351,2090,2031],{"class":368},[351,2092,2094,2097,2100,2103],{"class":353,"line":2093},26,[351,2095,2096],{"class":357},"    for",[351,2098,2099],{"class":368}," animal ",[351,2101,2102],{"class":357},"in",[351,2104,2105],{"class":368}," animals {\n",[351,2107,2109,2112,2114,2117],{"class":353,"line":2108},27,[351,2110,2111],{"class":368},"        animal",[351,2113,297],{"class":357},[351,2115,2116],{"class":361},"sound",[351,2118,2119],{"class":368},"();\n",[351,2121,2123],{"class":353,"line":2122},28,[351,2124,1684],{"class":368},[351,2126,2128],{"class":353,"line":2127},29,[351,2129,1297],{"class":368},[25,2131],{"className":2132},[45],[21,2134,2135,2136,2139,2140,2142,2143,2145,2146,215,2149,2152,2153,2155,2156,2159,2160,2162],{},"In this example, we define the ",[62,2137,2138],{},"Animal"," trait with a method ",[62,2141,2116],{},". We implement the ",[62,2144,2138],{}," trait for the ",[62,2147,2148],{},"Dog",[62,2150,2151],{},"Cat"," structs, each providing their own implementation of the ",[62,2154,2116],{}," method. We create a vector of boxed ",[62,2157,2158],{},"dyn Animal"," trait objects and iterate over them, calling the ",[62,2161,2116],{}," method dynamically at runtime.",[25,2164],{"className":2165},[36],[38,2167,2169],{"id":2168},"_2-ownership-and-borrowing","2. Ownership and Borrowing",[21,2171,2172],{},"Rust's ownership and borrowing system can be likened to a set of buckets representing different scopes. Each bucket represents a local scope, and the entities within the bucket are dropped or deallocated when the bucket or local scope goes out of scope. Understanding this analogy can help grasp the concepts of ownership and borrowing in Rust.",[21,2174,2175],{},"Imagine we have a bucket representing the main function scope. Inside this bucket, we can place entities, which can be either moved or borrowed when a new bucket (such as a function) is created. Let's explore these concepts further:",[25,2177],{"className":2178},[36],[21,2180,2181],{},[1176,2182,2183],{},"Example 1: Ownership (Moving)",[25,2185],{"className":2186},[45],[342,2188,2190],{"className":344,"code":2189,"filename":1185,"language":346,"meta":347,"style":347},"fn main() {\n    let string = String::from(\"Hello\");\n    let new_string = take_ownership(string);\n    // The string is moved to the `take_ownership` function and no longer accessible here.\n    println!(\"New string: {}\", new_string);\n}\n\nfn take_ownership(s: String) -> String {\n    // The ownership of the `s` string is transferred to this function.\n    // We can perform operations on `s` without affecting the original string.\n    s + \" World!\"\n}\n",[62,2191,2192,2200,2224,2239,2244,2256,2260,2264,2285,2290,2295,2305],{"__ignoreMap":347},[351,2193,2194,2196,2198],{"class":353,"line":354},[351,2195,1192],{"class":357},[351,2197,1195],{"class":361},[351,2199,1198],{"class":368},[351,2201,2202,2204,2207,2209,2212,2214,2217,2219,2222],{"class":353,"line":403},[351,2203,1203],{"class":357},[351,2205,2206],{"class":368}," string ",[351,2208,419],{"class":357},[351,2210,2211],{"class":361}," String",[351,2213,365],{"class":357},[351,2215,2216],{"class":361},"from",[351,2218,435],{"class":368},[351,2220,2221],{"class":438},"\"Hello\"",[351,2223,852],{"class":368},[351,2225,2226,2228,2231,2233,2236],{"class":353,"line":410},[351,2227,1203],{"class":357},[351,2229,2230],{"class":368}," new_string ",[351,2232,419],{"class":357},[351,2234,2235],{"class":361}," take_ownership",[351,2237,2238],{"class":368},"(string);\n",[351,2240,2241],{"class":353,"line":451},[351,2242,2243],{"class":668},"    // The string is moved to the `take_ownership` function and no longer accessible here.\n",[351,2245,2246,2248,2250,2253],{"class":353,"line":477},[351,2247,1266],{"class":361},[351,2249,435],{"class":368},[351,2251,2252],{"class":438},"\"New string: {}\"",[351,2254,2255],{"class":368},", new_string);\n",[351,2257,2258],{"class":353,"line":482},[351,2259,1297],{"class":368},[351,2261,2262],{"class":353,"line":517},[351,2263,407],{"emptyLinePlaceholder":406},[351,2265,2266,2268,2270,2273,2275,2277,2279,2281,2283],{"class":353,"line":538},[351,2267,1192],{"class":357},[351,2269,2235],{"class":361},[351,2271,2272],{"class":368},"(s",[351,2274,1355],{"class":357},[351,2276,2211],{"class":361},[351,2278,1369],{"class":368},[351,2280,1372],{"class":357},[351,2282,2211],{"class":361},[351,2284,1228],{"class":368},[351,2286,2287],{"class":353,"line":855},[351,2288,2289],{"class":668},"    // The ownership of the `s` string is transferred to this function.\n",[351,2291,2292],{"class":353,"line":860},[351,2293,2294],{"class":668},"    // We can perform operations on `s` without affecting the original string.\n",[351,2296,2297,2300,2302],{"class":353,"line":890},[351,2298,2299],{"class":368},"    s ",[351,2301,1253],{"class":357},[351,2303,2304],{"class":438}," \" World!\"\n",[351,2306,2307],{"class":353,"line":1470},[351,2308,1297],{"class":368},[25,2310],{"className":2311},[45],[21,2313,1523,2314,2317,2318,2321],{},[62,2315,2316],{},"take_ownership"," function takes ownership of the ",[62,2319,2320],{},"string"," and returns a new string. The original string is moved to the function, and it cannot be accessed in the main function afterward.",[25,2323],{"className":2324},[1161],[21,2326,2327],{},[1176,2328,2329],{},"Example 2: Borrowing (Referencing)",[25,2331],{"className":2332},[45],[342,2334,2336],{"className":344,"code":2335,"filename":1185,"language":346,"meta":347,"style":347},"fn main() {\n    let string = String::from(\"Hello\");\n    let length = calculate_length(&string);\n    // The `string` is still accessible in the main function after borrowing.\n    println!(\"Length of {}: {}\", string, length);\n}\n\nfn calculate_length(s: &String) -> usize {\n    // The `s` parameter is a reference to the original string.\n    // We can perform operations on the borrowed string without taking ownership.\n    s.len()\n}\n",[62,2337,2338,2346,2366,2385,2390,2402,2406,2410,2435,2440,2445,2458],{"__ignoreMap":347},[351,2339,2340,2342,2344],{"class":353,"line":354},[351,2341,1192],{"class":357},[351,2343,1195],{"class":361},[351,2345,1198],{"class":368},[351,2347,2348,2350,2352,2354,2356,2358,2360,2362,2364],{"class":353,"line":403},[351,2349,1203],{"class":357},[351,2351,2206],{"class":368},[351,2353,419],{"class":357},[351,2355,2211],{"class":361},[351,2357,365],{"class":357},[351,2359,2216],{"class":361},[351,2361,435],{"class":368},[351,2363,2221],{"class":438},[351,2365,852],{"class":368},[351,2367,2368,2370,2373,2375,2378,2380,2382],{"class":353,"line":410},[351,2369,1203],{"class":357},[351,2371,2372],{"class":368}," length ",[351,2374,419],{"class":357},[351,2376,2377],{"class":361}," calculate_length",[351,2379,435],{"class":368},[351,2381,624],{"class":357},[351,2383,2384],{"class":368},"string);\n",[351,2386,2387],{"class":353,"line":451},[351,2388,2389],{"class":668},"    // The `string` is still accessible in the main function after borrowing.\n",[351,2391,2392,2394,2396,2399],{"class":353,"line":477},[351,2393,1266],{"class":361},[351,2395,435],{"class":368},[351,2397,2398],{"class":438},"\"Length of {}: {}\"",[351,2400,2401],{"class":368},", string, length);\n",[351,2403,2404],{"class":353,"line":482},[351,2405,1297],{"class":368},[351,2407,2408],{"class":353,"line":517},[351,2409,407],{"emptyLinePlaceholder":406},[351,2411,2412,2414,2416,2418,2420,2423,2426,2428,2430,2433],{"class":353,"line":538},[351,2413,1192],{"class":357},[351,2415,2377],{"class":361},[351,2417,2272],{"class":368},[351,2419,1355],{"class":357},[351,2421,2422],{"class":357}," &",[351,2424,2425],{"class":361},"String",[351,2427,1369],{"class":368},[351,2429,1372],{"class":357},[351,2431,2432],{"class":361}," usize",[351,2434,1228],{"class":368},[351,2436,2437],{"class":353,"line":855},[351,2438,2439],{"class":668},"    // The `s` parameter is a reference to the original string.\n",[351,2441,2442],{"class":353,"line":860},[351,2443,2444],{"class":668},"    // We can perform operations on the borrowed string without taking ownership.\n",[351,2446,2447,2450,2452,2455],{"class":353,"line":890},[351,2448,2449],{"class":368},"    s",[351,2451,297],{"class":357},[351,2453,2454],{"class":361},"len",[351,2456,2457],{"class":368},"()\n",[351,2459,2460],{"class":353,"line":1470},[351,2461,1297],{"class":368},[25,2463],{"className":2464},[45],[21,2466,1523,2467,2470,2471,2473,2474,2477],{},[62,2468,2469],{},"calculate_length"," function borrows the ",[62,2472,2320],{}," by accepting a reference (",[62,2475,2476],{},"&string","). The reference allows the function to access the string's data without taking ownership. Therefore, the original string remains accessible in the main function even after borrowing.",[21,2479,2480],{},"By distinguishing between ownership (moving) and borrowing (referencing), Rust ensures memory safety and eliminates common bugs caused by multiple owners or invalid access to data. This system encourages developers to think carefully about how data is passed between scopes and promotes efficient and safe code.",[25,2482],{"className":2483},[36],[38,2485,2487],{"id":2486},"_3-pattern-matching","3. Pattern Matching",[21,2489,2490],{},"Rust's pattern matching is a versatile tool that allows developers to handle different scenarios and deconstruct complex data structures. It provides concise and expressive syntax, enabling effective case handling and value extraction. Let's delve into the concept of pattern matching in Rust:",[25,2492],{"className":2493},[36],[21,2495,2496],{},[1176,2497,2498],{},"Example 1: Matching Enums",[25,2500],{"className":2501},[45],[342,2503,2505],{"className":344,"code":2504,"filename":1185,"language":346,"meta":347,"style":347},"enum Message {\n    Quit,\n    Move { x: i32, y: i32 },\n    Write(String),\n}\n\nfn process_message(msg: Message) {\n    match msg {\n        Message::Quit => {\n            println!(\"Quit message received\");\n        }\n        Message::Move { x, y } => {\n            println!(\"Move to ({}, {})\", x, y);\n        }\n        Message::Write(text) => {\n            println!(\"Write message: {}\", text);\n        }\n    }\n}\n",[62,2506,2507,2517,2524,2546,2558,2562,2566,2582,2590,2605,2617,2622,2639,2651,2655,2671,2683,2687,2691],{"__ignoreMap":347},[351,2508,2509,2512,2515],{"class":353,"line":354},[351,2510,2511],{"class":357},"enum",[351,2513,2514],{"class":361}," Message",[351,2516,1228],{"class":368},[351,2518,2519,2522],{"class":353,"line":403},[351,2520,2521],{"class":361},"    Quit",[351,2523,796],{"class":368},[351,2525,2526,2529,2532,2534,2536,2539,2541,2543],{"class":353,"line":410},[351,2527,2528],{"class":361},"    Move",[351,2530,2531],{"class":368}," { x",[351,2533,1355],{"class":357},[351,2535,1366],{"class":361},[351,2537,2538],{"class":368},", y",[351,2540,1355],{"class":357},[351,2542,1366],{"class":361},[351,2544,2545],{"class":368}," },\n",[351,2547,2548,2551,2553,2555],{"class":353,"line":451},[351,2549,2550],{"class":361},"    Write",[351,2552,435],{"class":368},[351,2554,2425],{"class":361},[351,2556,2557],{"class":368},"),\n",[351,2559,2560],{"class":353,"line":477},[351,2561,1297],{"class":368},[351,2563,2564],{"class":353,"line":482},[351,2565,407],{"emptyLinePlaceholder":406},[351,2567,2568,2570,2573,2576,2578,2580],{"class":353,"line":517},[351,2569,1192],{"class":357},[351,2571,2572],{"class":361}," process_message",[351,2574,2575],{"class":368},"(msg",[351,2577,1355],{"class":357},[351,2579,2514],{"class":361},[351,2581,1905],{"class":368},[351,2583,2584,2587],{"class":353,"line":538},[351,2585,2586],{"class":357},"    match",[351,2588,2589],{"class":368}," msg {\n",[351,2591,2592,2595,2597,2600,2603],{"class":353,"line":855},[351,2593,2594],{"class":361},"        Message",[351,2596,365],{"class":357},[351,2598,2599],{"class":361},"Quit",[351,2601,2602],{"class":357}," =>",[351,2604,1228],{"class":368},[351,2606,2607,2610,2612,2615],{"class":353,"line":860},[351,2608,2609],{"class":361},"            println!",[351,2611,435],{"class":368},[351,2613,2614],{"class":438},"\"Quit message received\"",[351,2616,852],{"class":368},[351,2618,2619],{"class":353,"line":890},[351,2620,2621],{"class":368},"        }\n",[351,2623,2624,2626,2628,2631,2634,2637],{"class":353,"line":1470},[351,2625,2594],{"class":361},[351,2627,365],{"class":357},[351,2629,2630],{"class":361},"Move",[351,2632,2633],{"class":368}," { x, y } ",[351,2635,2636],{"class":357},"=>",[351,2638,1228],{"class":368},[351,2640,2641,2643,2645,2648],{"class":353,"line":1479},[351,2642,2609],{"class":361},[351,2644,435],{"class":368},[351,2646,2647],{"class":438},"\"Move to ({}, {})\"",[351,2649,2650],{"class":368},", x, y);\n",[351,2652,2653],{"class":353,"line":1499},[351,2654,2621],{"class":368},[351,2656,2657,2659,2661,2664,2667,2669],{"class":353,"line":1515},[351,2658,2594],{"class":361},[351,2660,365],{"class":357},[351,2662,2663],{"class":361},"Write",[351,2665,2666],{"class":368},"(text) ",[351,2668,2636],{"class":357},[351,2670,1228],{"class":368},[351,2672,2673,2675,2677,2680],{"class":353,"line":1739},[351,2674,2609],{"class":361},[351,2676,435],{"class":368},[351,2678,2679],{"class":438},"\"Write message: {}\"",[351,2681,2682],{"class":368},", text);\n",[351,2684,2685],{"class":353,"line":1744},[351,2686,2621],{"class":368},[351,2688,2689],{"class":353,"line":1768},[351,2690,1684],{"class":368},[351,2692,2693],{"class":353,"line":1977},[351,2694,1297],{"class":368},[25,2696],{"className":2697},[45],[21,2699,2700,2701,2704,2705,2708],{},"In this example, we define an enum called ",[62,2702,2703],{},"Message"," with different variants. The ",[62,2706,2707],{},"match"," keyword allows us to pattern match against each variant and execute the corresponding code block. Pattern matching simplifies the handling of different types of messages and ensures comprehensive coverage.",[25,2710],{"className":2711},[1161],[21,2713,2714],{},[1176,2715,2716],{},"Example 2: Destructuring Tuples",[25,2718],{"className":2719},[45],[342,2721,2723],{"className":344,"code":2722,"filename":1185,"language":346,"meta":347,"style":347},"fn print_coordinates(&(x, y): &(i32, i32)) {\n    println!(\"Coordinates: ({}, {})\", x, y);\n}\n\nfn main() {\n    let coordinates = (10, 20);\n    print_coordinates(&coordinates);\n}\n",[62,2724,2725,2754,2765,2769,2773,2781,2803,2815],{"__ignoreMap":347},[351,2726,2727,2729,2732,2734,2736,2739,2741,2743,2745,2747,2749,2751],{"class":353,"line":354},[351,2728,1192],{"class":357},[351,2730,2731],{"class":361}," print_coordinates",[351,2733,435],{"class":368},[351,2735,624],{"class":357},[351,2737,2738],{"class":368},"(x, y)",[351,2740,1355],{"class":357},[351,2742,2422],{"class":357},[351,2744,435],{"class":368},[351,2746,1395],{"class":361},[351,2748,253],{"class":368},[351,2750,1395],{"class":361},[351,2752,2753],{"class":368},")) {\n",[351,2755,2756,2758,2760,2763],{"class":353,"line":403},[351,2757,1266],{"class":361},[351,2759,435],{"class":368},[351,2761,2762],{"class":438},"\"Coordinates: ({}, {})\"",[351,2764,2650],{"class":368},[351,2766,2767],{"class":353,"line":410},[351,2768,1297],{"class":368},[351,2770,2771],{"class":353,"line":451},[351,2772,407],{"emptyLinePlaceholder":406},[351,2774,2775,2777,2779],{"class":353,"line":477},[351,2776,1192],{"class":357},[351,2778,1195],{"class":361},[351,2780,1198],{"class":368},[351,2782,2783,2785,2788,2790,2793,2796,2798,2801],{"class":353,"line":482},[351,2784,1203],{"class":357},[351,2786,2787],{"class":368}," coordinates ",[351,2789,419],{"class":357},[351,2791,2792],{"class":368}," (",[351,2794,2795],{"class":630},"10",[351,2797,253],{"class":368},[351,2799,2800],{"class":630},"20",[351,2802,852],{"class":368},[351,2804,2805,2808,2810,2812],{"class":353,"line":517},[351,2806,2807],{"class":361},"    print_coordinates",[351,2809,435],{"class":368},[351,2811,624],{"class":357},[351,2813,2814],{"class":368},"coordinates);\n",[351,2816,2817],{"class":353,"line":538},[351,2818,1297],{"class":368},[25,2820],{"className":2821},[45],[21,2823,2824,2825,2828,2829,2832,2833,2835],{},"Here, we have a function called ",[62,2826,2827],{},"print_coordinates"," that accepts a reference to a tuple ",[62,2830,2831],{},"(i32, i32)"," as a parameter. By using pattern matching, we can easily destructure the tuple into its individual components ",[62,2834,2738],{},". This enables us to access and utilize the coordinates within the function.",[21,2837,2838],{},"Pattern matching allows developers to handle complex scenarios and extract values from data structures in a concise and expressive manner. By embracing pattern matching, Rust programmers can write clean and structured code that effectively handles diverse cases.",[25,2840],{"className":2841},[36],[38,2843,2845],{"id":2844},"_4-lifetimes-in-rust-preventing-dangling-references-and-fixing-errors","4. Lifetimes in Rust: Preventing Dangling References and Fixing Errors",[21,2847,2848],{},"Rust's lifetime system ensures that references are always valid and prevents dangling references, which are references to memory that no longer exists. Lifetimes track the duration in which a reference is valid and enforce strict rules to guarantee memory safety. Understanding lifetimes, avoiding dangling references, and fixing related errors is crucial for writing reliable and efficient code in Rust.",[25,2850],{"className":2851},[36],[21,2853,2854],{},[1176,2855,2856],{},"Example 1: Dangling Reference",[25,2858],{"className":2859},[45],[342,2861,2863],{"className":344,"code":2862,"filename":1185,"language":346,"meta":347,"style":347},"fn get_string() -> &String {\n    let string = String::from(\"Hello\");\n    &string\n}\n\nfn main() {\n    let dangling_ref = get_string();\n    println!(\"Dangling reference: {}\", dangling_ref);\n    // Error: The `string` in `get_string` is dropped, leaving `dangling_ref`\n    // pointing to invalid memory.\n}\n",[62,2864,2865,2883,2903,2911,2915,2919,2927,2940,2952,2957,2962],{"__ignoreMap":347},[351,2866,2867,2869,2872,2875,2877,2879,2881],{"class":353,"line":354},[351,2868,1192],{"class":357},[351,2870,2871],{"class":361}," get_string",[351,2873,2874],{"class":368},"() ",[351,2876,1372],{"class":357},[351,2878,2422],{"class":357},[351,2880,2425],{"class":361},[351,2882,1228],{"class":368},[351,2884,2885,2887,2889,2891,2893,2895,2897,2899,2901],{"class":353,"line":403},[351,2886,1203],{"class":357},[351,2888,2206],{"class":368},[351,2890,419],{"class":357},[351,2892,2211],{"class":361},[351,2894,365],{"class":357},[351,2896,2216],{"class":361},[351,2898,435],{"class":368},[351,2900,2221],{"class":438},[351,2902,852],{"class":368},[351,2904,2905,2908],{"class":353,"line":410},[351,2906,2907],{"class":357},"    &",[351,2909,2910],{"class":368},"string\n",[351,2912,2913],{"class":353,"line":451},[351,2914,1297],{"class":368},[351,2916,2917],{"class":353,"line":477},[351,2918,407],{"emptyLinePlaceholder":406},[351,2920,2921,2923,2925],{"class":353,"line":482},[351,2922,1192],{"class":357},[351,2924,1195],{"class":361},[351,2926,1198],{"class":368},[351,2928,2929,2931,2934,2936,2938],{"class":353,"line":517},[351,2930,1203],{"class":357},[351,2932,2933],{"class":368}," dangling_ref ",[351,2935,419],{"class":357},[351,2937,2871],{"class":361},[351,2939,2119],{"class":368},[351,2941,2942,2944,2946,2949],{"class":353,"line":538},[351,2943,1266],{"class":361},[351,2945,435],{"class":368},[351,2947,2948],{"class":438},"\"Dangling reference: {}\"",[351,2950,2951],{"class":368},", dangling_ref);\n",[351,2953,2954],{"class":353,"line":855},[351,2955,2956],{"class":668},"    // Error: The `string` in `get_string` is dropped, leaving `dangling_ref`\n",[351,2958,2959],{"class":353,"line":860},[351,2960,2961],{"class":668},"    // pointing to invalid memory.\n",[351,2963,2964],{"class":353,"line":890},[351,2965,1297],{"class":368},[25,2967],{"className":2968},[45],[21,2970,1523,2971,2974,2975,2977,2978,2980,2981,2984,2985,2988],{},[62,2972,2973],{},"get_string"," function creates a ",[62,2976,2425],{}," and returns a reference to it. However, since the reference's lifetime is tied to the local scope of the ",[62,2979,2973],{}," function, it becomes a dangling reference once the function ends. When the ",[62,2982,2983],{},"dangling_ref"," is used in the ",[62,2986,2987],{},"main"," function, it points to invalid memory, leading to undefined behavior and a potential crash. Rust's lifetime system prevents this scenario by disallowing dangling references at compile time.",[25,2990],{"className":2991},[1161],[21,2993,2994],{},[1176,2995,2996],{},"Example 2: Proper Lifetime Annotation",[25,2998],{"className":2999},[45],[342,3001,3003],{"className":344,"code":3002,"filename":1185,"language":346,"meta":347,"style":347},"fn get_longest\u003C'a>(x: &'a str, y: &'a str) -> &'a str {\n    if x.len() > y.len() {\n        x\n    } else {\n        y\n    }\n}\n\nfn main() {\n    let string1 = String::from(\"Hello\");\n    let result;\n    {\n        let string2 = String::from(\"World\");\n        result = get_longest(&string1, &string2);\n        println!(\"Longest string: {}\", result);\n    }\n    // Both `string1` and `string2` are still valid until this point, so the\n    // reference `result` is not dangling.\n}\n",[62,3004,3005,3058,3079,3084,3094,3099,3103,3107,3111,3119,3140,3147,3152,3174,3195,3207,3211,3216,3221],{"__ignoreMap":347},[351,3006,3007,3009,3012,3015,3017,3020,3022,3024,3027,3029,3032,3034,3036,3038,3040,3042,3044,3046,3048,3050,3052,3054,3056],{"class":353,"line":354},[351,3008,1192],{"class":357},[351,3010,3011],{"class":361}," get_longest",[351,3013,3014],{"class":368},"\u003C'",[351,3016,291],{"class":361},[351,3018,3019],{"class":368},">(x",[351,3021,1355],{"class":357},[351,3023,2422],{"class":357},[351,3025,3026],{"class":368},"'",[351,3028,291],{"class":361},[351,3030,3031],{"class":361}," str",[351,3033,2538],{"class":368},[351,3035,1355],{"class":357},[351,3037,2422],{"class":357},[351,3039,3026],{"class":368},[351,3041,291],{"class":361},[351,3043,3031],{"class":361},[351,3045,1369],{"class":368},[351,3047,1372],{"class":357},[351,3049,2422],{"class":357},[351,3051,3026],{"class":368},[351,3053,291],{"class":361},[351,3055,3031],{"class":361},[351,3057,1228],{"class":368},[351,3059,3060,3063,3066,3068,3070,3073,3075,3077],{"class":353,"line":403},[351,3061,3062],{"class":357},"    if",[351,3064,3065],{"class":368}," x",[351,3067,297],{"class":357},[351,3069,2454],{"class":361},[351,3071,3072],{"class":368},"() > y",[351,3074,297],{"class":357},[351,3076,2454],{"class":361},[351,3078,1198],{"class":368},[351,3080,3081],{"class":353,"line":410},[351,3082,3083],{"class":368},"        x\n",[351,3085,3086,3089,3092],{"class":353,"line":451},[351,3087,3088],{"class":368},"    } ",[351,3090,3091],{"class":357},"else",[351,3093,1228],{"class":368},[351,3095,3096],{"class":353,"line":477},[351,3097,3098],{"class":368},"        y\n",[351,3100,3101],{"class":353,"line":482},[351,3102,1684],{"class":368},[351,3104,3105],{"class":353,"line":517},[351,3106,1297],{"class":368},[351,3108,3109],{"class":353,"line":538},[351,3110,407],{"emptyLinePlaceholder":406},[351,3112,3113,3115,3117],{"class":353,"line":855},[351,3114,1192],{"class":357},[351,3116,1195],{"class":361},[351,3118,1198],{"class":368},[351,3120,3121,3123,3126,3128,3130,3132,3134,3136,3138],{"class":353,"line":860},[351,3122,1203],{"class":357},[351,3124,3125],{"class":368}," string1 ",[351,3127,419],{"class":357},[351,3129,2211],{"class":361},[351,3131,365],{"class":357},[351,3133,2216],{"class":361},[351,3135,435],{"class":368},[351,3137,2221],{"class":438},[351,3139,852],{"class":368},[351,3141,3142,3144],{"class":353,"line":890},[351,3143,1203],{"class":357},[351,3145,3146],{"class":368}," result;\n",[351,3148,3149],{"class":353,"line":1470},[351,3150,3151],{"class":368},"    {\n",[351,3153,3154,3156,3159,3161,3163,3165,3167,3169,3172],{"class":353,"line":1479},[351,3155,1233],{"class":357},[351,3157,3158],{"class":368}," string2 ",[351,3160,419],{"class":357},[351,3162,2211],{"class":361},[351,3164,365],{"class":357},[351,3166,2216],{"class":361},[351,3168,435],{"class":368},[351,3170,3171],{"class":438},"\"World\"",[351,3173,852],{"class":368},[351,3175,3176,3179,3181,3183,3185,3187,3190,3192],{"class":353,"line":1499},[351,3177,3178],{"class":368},"        result ",[351,3180,419],{"class":357},[351,3182,3011],{"class":361},[351,3184,435],{"class":368},[351,3186,624],{"class":357},[351,3188,3189],{"class":368},"string1, ",[351,3191,624],{"class":357},[351,3193,3194],{"class":368},"string2);\n",[351,3196,3197,3199,3201,3204],{"class":353,"line":1515},[351,3198,1910],{"class":361},[351,3200,435],{"class":368},[351,3202,3203],{"class":438},"\"Longest string: {}\"",[351,3205,3206],{"class":368},", result);\n",[351,3208,3209],{"class":353,"line":1739},[351,3210,1684],{"class":368},[351,3212,3213],{"class":353,"line":1744},[351,3214,3215],{"class":668},"    // Both `string1` and `string2` are still valid until this point, so the\n",[351,3217,3218],{"class":353,"line":1768},[351,3219,3220],{"class":668},"    // reference `result` is not dangling.\n",[351,3222,3223],{"class":353,"line":1977},[351,3224,1297],{"class":368},[25,3226],{"className":3227},[45],[21,3229,3230,3231,3234,3235,3238,3239,215,3241,3244,3245,3247,3248,215,3251,3254,3255,3257,3258,3261],{},"In this updated example, the ",[62,3232,3233],{},"get_longest"," function has a lifetime annotation ",[62,3236,3237],{},"'a"," that indicates the references ",[62,3240,1306],{},[62,3242,3243],{},"y"," have the same lifetime. The main function creates two ",[62,3246,2425],{}," instances, ",[62,3249,3250],{},"string1",[62,3252,3253],{},"string2",", and passes their references to ",[62,3256,3233],{},". Since the lifetime of the references is properly managed, the returned reference ",[62,3259,3260],{},"result"," remains valid and does not become a dangling reference.",[25,3263],{"className":3264},[1161],[21,3266,3267],{},[1176,3268,3269],{},"Example 3: Fixing the Dangling Reference Error",[25,3271],{"className":3272},[45],[342,3274,3276],{"className":344,"code":3275,"filename":1185,"language":346,"meta":347,"style":347},"fn get_string() -> String {\n    let string = String::from(\"Hello\");\n    string\n}\n\nfn main() {\n    let valid_string = get_string();\n    let valid_ref = &valid_string;\n    println!(\"Valid reference: {}\", valid_ref);\n    // The `valid_string` is still valid, and the reference `valid_ref` can be\n    // safely used.\n}\n",[62,3277,3278,3292,3312,3317,3321,3325,3333,3346,3360,3372,3377,3382],{"__ignoreMap":347},[351,3279,3280,3282,3284,3286,3288,3290],{"class":353,"line":354},[351,3281,1192],{"class":357},[351,3283,2871],{"class":361},[351,3285,2874],{"class":368},[351,3287,1372],{"class":357},[351,3289,2211],{"class":361},[351,3291,1228],{"class":368},[351,3293,3294,3296,3298,3300,3302,3304,3306,3308,3310],{"class":353,"line":403},[351,3295,1203],{"class":357},[351,3297,2206],{"class":368},[351,3299,419],{"class":357},[351,3301,2211],{"class":361},[351,3303,365],{"class":357},[351,3305,2216],{"class":361},[351,3307,435],{"class":368},[351,3309,2221],{"class":438},[351,3311,852],{"class":368},[351,3313,3314],{"class":353,"line":410},[351,3315,3316],{"class":368},"    string\n",[351,3318,3319],{"class":353,"line":451},[351,3320,1297],{"class":368},[351,3322,3323],{"class":353,"line":477},[351,3324,407],{"emptyLinePlaceholder":406},[351,3326,3327,3329,3331],{"class":353,"line":482},[351,3328,1192],{"class":357},[351,3330,1195],{"class":361},[351,3332,1198],{"class":368},[351,3334,3335,3337,3340,3342,3344],{"class":353,"line":517},[351,3336,1203],{"class":357},[351,3338,3339],{"class":368}," valid_string ",[351,3341,419],{"class":357},[351,3343,2871],{"class":361},[351,3345,2119],{"class":368},[351,3347,3348,3350,3353,3355,3357],{"class":353,"line":538},[351,3349,1203],{"class":357},[351,3351,3352],{"class":368}," valid_ref ",[351,3354,419],{"class":357},[351,3356,2422],{"class":357},[351,3358,3359],{"class":368},"valid_string;\n",[351,3361,3362,3364,3366,3369],{"class":353,"line":855},[351,3363,1266],{"class":361},[351,3365,435],{"class":368},[351,3367,3368],{"class":438},"\"Valid reference: {}\"",[351,3370,3371],{"class":368},", valid_ref);\n",[351,3373,3374],{"class":353,"line":860},[351,3375,3376],{"class":668},"    // The `valid_string` is still valid, and the reference `valid_ref` can be\n",[351,3378,3379],{"class":353,"line":890},[351,3380,3381],{"class":668},"    // safely used.\n",[351,3383,3384],{"class":353,"line":1470},[351,3385,1297],{"class":368},[25,3387],{"className":3388},[45],[21,3390,3391,3392,3394,3395,3397,3398,3400,3401,3403,3404,3406,3407,3410,3411,3414],{},"In this example, we modify the ",[62,3393,2973],{}," function to return the actual ",[62,3396,2425],{}," instead of a reference to it. By doing so, the ownership of the ",[62,3399,2425],{}," is transferred to the caller, ensuring that the string remains valid outside the function scope. In the ",[62,3402,2987],{}," function, we assign the returned ",[62,3405,2425],{}," to the ",[62,3408,3409],{},"valid_string"," variable and create a valid reference, ",[62,3412,3413],{},"valid_ref",", to it. This approach avoids the issue of dangling references altogether, as the data remains accessible and valid throughout its lifetime.",[21,3416,3417],{},"By returning the actual owned value rather than a reference in situations where it makes sense, developers can avoid dangling references and leverage Rust's ownership model to ensure memory safety. It's important to consider the lifetime requirements and choose the appropriate approach based on the specific use case.",[25,3419],{"className":3420},[36],[38,3422,3424],{"id":3423},"_5-single-mutable-reference-ensuring-mutability-and-memory-safety","5. Single Mutable Reference: Ensuring Mutability and Memory Safety",[21,3426,3427],{},"In Rust, the concept of ownership extends to mutable references, ensuring that there is only a single mutable reference to a variable within a particular scope. This design choice enforces strict rules to prevent data races and guarantee memory safety, making Rust code highly reliable. Understanding why Rust allows only one mutable reference and how it enhances the safety and predictability of your programs is essential.",[21,3429,3430],{},"The restriction of having a single mutable reference to a variable prevents potential issues such as data races, where multiple threads concurrently access and modify the same data, leading to unpredictable and erroneous behavior. By allowing only one mutable reference, Rust avoids scenarios where multiple references could simultaneously modify a value and cause race conditions.",[25,3432],{"className":3433},[36],[21,3435,3436],{},[1176,3437,3438],{},"Example 1: Single Mutable Reference in Action",[25,3440],{"className":3441},[45],[342,3443,3445],{"className":344,"code":3444,"filename":1185,"language":346,"meta":347,"style":347},"fn main() {\n    let mut number = 5;\n    let reference = &mut number; // Mutable reference\n    *reference += 1; // Modifying the value through the reference\n    println!(\"Modified number: {}\", number); // Output: Modified number: 6\n}\n",[62,3446,3447,3455,3471,3489,3508,3523],{"__ignoreMap":347},[351,3448,3449,3451,3453],{"class":353,"line":354},[351,3450,1192],{"class":357},[351,3452,1195],{"class":361},[351,3454,1198],{"class":368},[351,3456,3457,3459,3462,3465,3467,3469],{"class":353,"line":403},[351,3458,1203],{"class":357},[351,3460,3461],{"class":357}," mut",[351,3463,3464],{"class":368}," number ",[351,3466,419],{"class":357},[351,3468,1211],{"class":630},[351,3470,448],{"class":368},[351,3472,3473,3475,3478,3480,3483,3486],{"class":353,"line":410},[351,3474,1203],{"class":357},[351,3476,3477],{"class":368}," reference ",[351,3479,419],{"class":357},[351,3481,3482],{"class":357}," &mut",[351,3484,3485],{"class":368}," number; ",[351,3487,3488],{"class":668},"// Mutable reference\n",[351,3490,3491,3494,3497,3500,3503,3505],{"class":353,"line":451},[351,3492,3493],{"class":357},"    *",[351,3495,3496],{"class":368},"reference ",[351,3498,3499],{"class":357},"+=",[351,3501,3502],{"class":630}," 1",[351,3504,665],{"class":368},[351,3506,3507],{"class":668},"// Modifying the value through the reference\n",[351,3509,3510,3512,3514,3517,3520],{"class":353,"line":477},[351,3511,1266],{"class":361},[351,3513,435],{"class":368},[351,3515,3516],{"class":438},"\"Modified number: {}\"",[351,3518,3519],{"class":368},", number); ",[351,3521,3522],{"class":668},"// Output: Modified number: 6\n",[351,3524,3525],{"class":353,"line":482},[351,3526,1297],{"class":368},[25,3528],{"className":3529},[45],[21,3531,3532,3533,3536,3537,3540,3541,3544,3545,3548,3549,3551,3552,3554,3555,3557],{},"In this example, we define a mutable variable ",[62,3534,3535],{},"number"," and then create a mutable reference ",[62,3538,3539],{},"reference"," to it using the ",[62,3542,3543],{},"&mut"," syntax. By dereferencing the reference with ",[62,3546,3547],{},"*reference",", we can modify the value of ",[62,3550,3535],{},". In this case, we increment ",[62,3553,3535],{}," by 1. As a result, the value of ",[62,3556,3535],{}," is changed to 6, and we can observe the modified value when we print it.",[21,3559,3560],{},"By allowing only one mutable reference to a variable, Rust ensures that modifications are well-controlled, preventing potential conflicts and race conditions. This restriction guarantees that concurrent access to mutable data is properly synchronized, making Rust programs inherently thread-safe and avoiding subtle bugs caused by data races.",[21,3562,3563],{},"While the limitation of a single mutable reference might require some adjustments in how you structure your code, it contributes to the overall safety and reliability of your Rust programs. It encourages explicit and intentional control over mutable access, reducing the chances of programming errors and making it easier to reason about code behavior.",[21,3565,3566,3567,253,3570,3573,3574,3577],{},"In situations where you need to modify data from different parts of your code simultaneously, Rust provides mechanisms like interior mutability, which allows for controlled mutability through specific types such as ",[62,3568,3569],{},"Cell",[62,3571,3572],{},"RefCell",", or ",[62,3575,3576],{},"Mutex",". These constructs ensure that mutations are synchronized and safe, even in multi-threaded scenarios.",[25,3579],{"className":3580},[36],[38,3582,3584],{"id":3583},"_6-simultaneous-access-with-synchronization-primitives","6. Simultaneous Access with Synchronization Primitives",[21,3586,3587],{},"While Rust's ownership and borrowing model restricts simultaneous mutable access to a variable, there are cases where you genuinely need multiple references for concurrent read or write operations. Rust provides synchronization primitives that allow controlled and safe simultaneous access to shared data, ensuring thread safety and preventing data races. Let's explore one such synchronization primitive, the mutex, and how it enables concurrent access without compromising safety.",[25,3589],{"className":3590},[1161],[1151,3592,3594],{"id":3593},"mutex-synchronizing-exclusive-access","Mutex: Synchronizing Exclusive Access",[21,3596,3597],{},"One of the most commonly used synchronization primitives in Rust is the mutex (short for mutual exclusion). A mutex allows multiple threads to access a shared resource, but only one thread can have exclusive access to it at a time. Other threads must wait until the owning thread releases the lock.",[21,3599,3600],{},[1176,3601,3602],{},"Example: Simultaneous Access with Mutex",[25,3604],{"className":3605},[45],[342,3607,3609],{"className":344,"code":3608,"filename":1185,"language":346,"meta":347,"style":347},"use std::sync::{Mutex, Arc};\nuse std::thread;\n\nfn main() {\n    let counter = Arc::new(Mutex::new(0));\n    let mut handles = vec![];\n\n    for _ in 0..10 {\n        let counter = Arc::clone(&counter);\n        let handle = thread::spawn(move || {\n            let mut data = counter.lock().unwrap();\n            *data += 1;\n        });\n        handles.push(handle);\n    }\n\n    for handle in handles {\n        handle.join().expect(\"Thread panicked\");\n    }\n\n    println!(\"Counter value: {:?}\", *counter.lock().unwrap());\n}\n",[62,3610,3611,3636,3647,3651,3659,3689,3705,3709,3728,3749,3776,3804,3818,3823,3836,3840,3844,3855,3879,3883,3887,3914],{"__ignoreMap":347},[351,3612,3613,3615,3618,3620,3623,3625,3627,3629,3631,3634],{"class":353,"line":354},[351,3614,358],{"class":357},[351,3616,3617],{"class":361}," std",[351,3619,365],{"class":357},[351,3621,3622],{"class":361},"sync",[351,3624,365],{"class":357},[351,3626,369],{"class":368},[351,3628,3576],{"class":361},[351,3630,253],{"class":368},[351,3632,3633],{"class":361},"Arc",[351,3635,813],{"class":368},[351,3637,3638,3640,3642,3644],{"class":353,"line":403},[351,3639,358],{"class":357},[351,3641,3617],{"class":361},[351,3643,365],{"class":357},[351,3645,3646],{"class":368},"thread;\n",[351,3648,3649],{"class":353,"line":410},[351,3650,407],{"emptyLinePlaceholder":406},[351,3652,3653,3655,3657],{"class":353,"line":451},[351,3654,1192],{"class":357},[351,3656,1195],{"class":361},[351,3658,1198],{"class":368},[351,3660,3661,3663,3665,3667,3670,3672,3674,3676,3678,3680,3682,3684,3686],{"class":353,"line":477},[351,3662,1203],{"class":357},[351,3664,587],{"class":368},[351,3666,419],{"class":357},[351,3668,3669],{"class":361}," Arc",[351,3671,365],{"class":357},[351,3673,532],{"class":361},[351,3675,435],{"class":368},[351,3677,3576],{"class":361},[351,3679,365],{"class":357},[351,3681,532],{"class":361},[351,3683,435],{"class":368},[351,3685,1005],{"class":630},[351,3687,3688],{"class":368},"));\n",[351,3690,3691,3693,3695,3698,3700,3702],{"class":353,"line":482},[351,3692,1203],{"class":357},[351,3694,3461],{"class":357},[351,3696,3697],{"class":368}," handles ",[351,3699,419],{"class":357},[351,3701,2064],{"class":361},[351,3703,3704],{"class":368},"[];\n",[351,3706,3707],{"class":353,"line":517},[351,3708,407],{"emptyLinePlaceholder":406},[351,3710,3711,3713,3716,3718,3721,3724,3726],{"class":353,"line":538},[351,3712,2096],{"class":357},[351,3714,3715],{"class":368}," _ ",[351,3717,2102],{"class":357},[351,3719,3720],{"class":630}," 0",[351,3722,3723],{"class":357},"..",[351,3725,2795],{"class":630},[351,3727,1228],{"class":368},[351,3729,3730,3732,3734,3736,3738,3740,3742,3744,3746],{"class":353,"line":855},[351,3731,1233],{"class":357},[351,3733,587],{"class":368},[351,3735,419],{"class":357},[351,3737,3669],{"class":361},[351,3739,365],{"class":357},[351,3741,604],{"class":361},[351,3743,435],{"class":368},[351,3745,624],{"class":357},[351,3747,3748],{"class":368},"counter);\n",[351,3750,3751,3753,3756,3758,3761,3763,3766,3768,3771,3774],{"class":353,"line":860},[351,3752,1233],{"class":357},[351,3754,3755],{"class":368}," handle ",[351,3757,419],{"class":357},[351,3759,3760],{"class":361}," thread",[351,3762,365],{"class":357},[351,3764,3765],{"class":361},"spawn",[351,3767,435],{"class":368},[351,3769,3770],{"class":357},"move",[351,3772,3773],{"class":357}," ||",[351,3775,1228],{"class":368},[351,3777,3778,3781,3783,3786,3788,3790,3792,3795,3797,3799,3802],{"class":353,"line":890},[351,3779,3780],{"class":357},"            let",[351,3782,3461],{"class":357},[351,3784,3785],{"class":368}," data ",[351,3787,419],{"class":357},[351,3789,649],{"class":368},[351,3791,297],{"class":357},[351,3793,3794],{"class":361},"lock",[351,3796,469],{"class":368},[351,3798,297],{"class":357},[351,3800,3801],{"class":361},"unwrap",[351,3803,2119],{"class":368},[351,3805,3806,3809,3812,3814,3816],{"class":353,"line":1470},[351,3807,3808],{"class":357},"            *",[351,3810,3811],{"class":368},"data ",[351,3813,3499],{"class":357},[351,3815,3502],{"class":630},[351,3817,448],{"class":368},[351,3819,3820],{"class":353,"line":1479},[351,3821,3822],{"class":368},"        });\n",[351,3824,3825,3828,3830,3833],{"class":353,"line":1499},[351,3826,3827],{"class":368},"        handles",[351,3829,297],{"class":357},[351,3831,3832],{"class":361},"push",[351,3834,3835],{"class":368},"(handle);\n",[351,3837,3838],{"class":353,"line":1515},[351,3839,1684],{"class":368},[351,3841,3842],{"class":353,"line":1739},[351,3843,407],{"emptyLinePlaceholder":406},[351,3845,3846,3848,3850,3852],{"class":353,"line":1744},[351,3847,2096],{"class":357},[351,3849,3755],{"class":368},[351,3851,2102],{"class":357},[351,3853,3854],{"class":368}," handles {\n",[351,3856,3857,3860,3862,3865,3867,3869,3872,3874,3877],{"class":353,"line":1768},[351,3858,3859],{"class":368},"        handle",[351,3861,297],{"class":357},[351,3863,3864],{"class":361},"join",[351,3866,469],{"class":368},[351,3868,297],{"class":357},[351,3870,3871],{"class":361},"expect",[351,3873,435],{"class":368},[351,3875,3876],{"class":438},"\"Thread panicked\"",[351,3878,852],{"class":368},[351,3880,3881],{"class":353,"line":1977},[351,3882,1684],{"class":368},[351,3884,3885],{"class":353,"line":1982},[351,3886,407],{"emptyLinePlaceholder":406},[351,3888,3889,3891,3893,3896,3898,3900,3902,3904,3906,3908,3910,3912],{"class":353,"line":1991},[351,3890,1266],{"class":361},[351,3892,435],{"class":368},[351,3894,3895],{"class":438},"\"Counter value: {:?}\"",[351,3897,253],{"class":368},[351,3899,1671],{"class":357},[351,3901,377],{"class":368},[351,3903,297],{"class":357},[351,3905,3794],{"class":361},[351,3907,469],{"class":368},[351,3909,297],{"class":357},[351,3911,3801],{"class":361},[351,3913,607],{"class":368},[351,3915,3916],{"class":353,"line":2010},[351,3917,1297],{"class":368},[25,3919],{"className":3920},[45],[21,3922,3923,3924,3926,3927,3929,3930,3932],{},"In this example, we use an additional synchronization primitive, ",[62,3925,3633],{}," (short for atomic reference counting), to share ownership of the mutex ",[62,3928,377],{}," among multiple threads. ",[62,3931,3633],{}," enables multiple ownership of a value across threads, ensuring its reference count is properly tracked.",[21,3934,3935,3936,3938,3939,3942,3943,3945,3946,3948,3949,3952],{},"We create an ",[62,3937,3633],{}," around the mutex ",[62,3940,3941],{},"Mutex::new(0)",", which initializes the shared counter to zero. Each thread receives a cloned ",[62,3944,3633],{}," reference to the counter, incrementing it by acquiring a lock on the mutex using the ",[62,3947,3794],{}," method. Once the increment is complete, the lock is automatically released as the ",[62,3950,3951],{},"data"," variable goes out of scope.",[21,3954,3955,3956,3958],{},"By using ",[62,3957,3633],{}," to share ownership of the mutex, we ensure that each thread can safely access and modify the counter concurrently. The mutex enforces exclusive access, preventing data races and guaranteeing consistent results.",[21,3960,3961,3962,3964],{},"Using synchronization primitives like mutexes and smart pointers like ",[62,3963,3633],{}," enables Rust programmers to handle cases where simultaneous access to shared data is necessary while ensuring thread safety and preventing data races. By combining these primitives with Rust's ownership and borrowing model, you can build concurrent applications that are both safe and efficient.",[25,3966],{"className":3967},[36],[38,3969,3971],{"id":3970},"conclusion","Conclusion",[21,3973,3974],{},"In summary, Rust is a programming language that offers a unique set of features and concepts to developers. Its ownership and borrowing system ensures memory safety and eliminates common bugs, while pattern matching provides a concise way to handle complex data structures. Lifetimes enforce reference management and prevent dangling references.",[21,3976,3977],{},"Rust's synchronization primitives enable safe concurrent access to shared data, and its support for functional programming and object-oriented programming allows for expressive and modular code. Immutability by default, higher-order functions, structs, methods, traits, and polymorphism contribute to Rust's versatility.",[21,3979,3980],{},"By mastering these core features, developers can write robust, efficient, and safe code in Rust. The language's growing ecosystem and active community make it an exciting choice for a wide range of applications. Embrace Rust's philosophy of safe systems programming and unlock the potential of this powerful language.",[25,3982],{"className":3983},[36],[932,3985],{},[25,3987],{"className":3988},[36],[21,3990,3991],{},[3992,3993,3994,3995,4000],"em",{},"Originally published on ",[291,3996,3999],{"href":3997,"rel":3998},"https://medium.com/@dev.davexoyinbo/embracing-perfection-a-journey-into-rust-programming-a524de4f053f",[295],"Medium"," on June 20, 2023.",[938,4002,4003],{},"html pre.shiki code .snl16, html code.shiki .snl16{--shiki-default:#F97583}html pre.shiki code .svObZ, html code.shiki .svObZ{--shiki-default:#B392F0}html pre.shiki code .s95oV, html code.shiki .s95oV{--shiki-default:#E1E4E8}html pre.shiki code .sDLfK, html code.shiki .sDLfK{--shiki-default:#79B8FF}html pre.shiki code .sAwPA, html code.shiki .sAwPA{--shiki-default:#6A737D}html pre.shiki code .sU2Wk, html code.shiki .sU2Wk{--shiki-default:#9ECBFF}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);}",{"title":347,"searchDepth":403,"depth":403,"links":4005},[4006,4007,4011,4012,4013,4014,4015,4018],{"id":1132,"depth":403,"text":1133},{"id":1142,"depth":403,"text":1143,"children":4008},[4009,4010],{"id":1153,"depth":410,"text":1154},{"id":1555,"depth":410,"text":1556},{"id":2168,"depth":403,"text":2169},{"id":2486,"depth":403,"text":2487},{"id":2844,"depth":403,"text":2845},{"id":3423,"depth":403,"text":3424},{"id":3583,"depth":403,"text":3584,"children":4016},[4017],{"id":3593,"depth":410,"text":3594},{"id":3970,"depth":403,"text":3971},"2023-06-20T00:00:00.000Z","Exploring Rust's core features and concepts that make it a powerful and compelling language for developers seeking memory safety and performance.",null,{},"/engineering-logs/embracing-perfection-rust","11 min read",{"title":1108,"description":4020},"engineering-logs/embracing-perfection-rust",[346,4028,4029,4030,4031],"programming","backend","systems","memory-safety","TDr9G3tuf0NroZecA6wQedb3zhg_jnp3eLqPECXwDRU",{"id":4034,"title":4035,"author":6,"body":4036,"date":4310,"description":4311,"extension":953,"image_url":4021,"meta":4312,"navigation":406,"original_url":4298,"path":4313,"readTime":4314,"seo":4315,"stem":4316,"tags":4317,"__hash__":4324},"engineeringLogs/engineering-logs/programming-soft-skills.md","Is Programming Enough? The Tales of a Software Engineer",{"type":8,"value":4037,"toc":4301},[4038,4042,4045,4048,4051,4054,4057,4059,4062,4065,4068,4071,4074,4077,4081,4084,4087,4093,4096,4099,4102,4105,4108,4112,4115,4118,4121,4124,4127,4130,4133,4136,4139,4142,4145,4148,4152,4155,4158,4161,4164,4167,4170,4173,4176,4196,4199,4204,4207,4211,4214,4217,4222,4225,4228,4231,4235,4238,4241,4244,4247,4252,4258,4264,4270,4273,4275,4278,4281,4284,4287,4289,4292],[11,4039],{"className":4040,"date":4041},[14],"2024-04-28",[17,4043,4035],{"id":4044},"is-programming-enough-the-tales-of-a-software-engineer",[21,4046,4047],{},"Exploring the essential soft skills beyond programming that software engineers need to succeed in the business world",[25,4049],{"className":4050},[28],[30,4052],{":tags":4053},"[\"Software Engineering\", \"Career Development\", \"Soft Skills\", \"Communication\", \"Collaboration\", \"Problem Solving\", \"Business\"]",[25,4055],{"className":4056},[36],[38,4058,1133],{"id":1132},[21,4060,4061],{},"When the topic of software engineering is discussed, it is often around hard skills like programming, design, DevOps and what not. A key aspect of software engineering — at the risk of offending the hobbyists — is the aspect of making money. Money is (usually) the driving force of a product and it becomes an issue very fast given that most software are business driven.",[25,4063],{"className":4064},[45],[21,4066,4067],{},"Many companies have drowned not because of the fact that they don't have experienced engineers but the fact that other aspects like management, communication, and most importantly, flexibility were not adequately developed. As an example, \"The Peer\", a Nigerian startup which raised about $2.1 million announced they would be shutting down and returning $350 thousand to investors. One of the reasons they said they are shutting down is because they couldn't find a good \"product-market fit.\"",[25,4069],{"className":4070},[45],[21,4072,4073],{},"In as much as it is hard to make a good product, and the fact that the success rate of businesses even for business owners with experience is about 30%, it becomes more and more glaring that hard skills in software engineering, even though very important, are not enough in the business world.",[25,4075],{"className":4076},[36],[38,4078,4080],{"id":4079},"so-what-matters","So What Matters?",[21,4082,4083],{},"In \"The Lean Startup,\" Eric Ries emphasizes the importance of communication and incremental growth throughout the book, but a particularly relevant reference can be found in Chapter 3, \"Experiment.\" Here's a passage that highlights these principles:",[25,4085],{"className":4086},[45],[4088,4089,4090],"blockquote",{},[21,4091,4092],{},"\"Entrepreneurs are more like artists, who must interpret incomplete and conflicting information, than traditional managers, who largely preside over well-defined problems. Instead of making complex five-year plans, we need to create a framework for learning and experimentation.\"",[25,4094],{"className":4095},[45],[21,4097,4098],{},"This passage explains the necessity of constant communication and feedback loops with customers, as well as the value of incremental growth through iterative experimentation rather than relying on rigid long-term plans.",[25,4100],{"className":4101},[45],[21,4103,4104],{},"And this brings us to the first soft skill a software engineer can use to improve himself and increase his relevance — communication.",[25,4106],{"className":4107},[36],[38,4109,4111],{"id":4110},"_1-communication","1. Communication",[21,4113,4114],{},"As a software engineer, I once encountered a situation where active listening proved invaluable. We were developing a new feature for a product, and a client called in, frustrated and confused about how the new interface worked. Instead of jumping to explain or defend the design, I took a step back and listened patiently.",[25,4116],{"className":4117},[45],[21,4119,4120],{},"The client vented about how the new layout made it difficult to find specific functionalities they used frequently. As they spoke, I made note of the features they mentioned and the confusions they expressed with the current workflow.",[25,4122],{"className":4123},[45],[21,4125,4126],{},"Through active listening, I discovered that the core issue wasn't necessarily the design itself, but a lack of clarity in the user flow. The client's frustration stemmed from a disconnect between their mental model and the way the new interface presented information.",[25,4128],{"className":4129},[45],[21,4131,4132],{},"With this understanding, I could approach the situation collaboratively. I explained the reasoning behind the design choices and then worked with the client to identify potential improvements that addressed their concerns. We explored ways to streamline the workflow and make the necessary features more easily discoverable.",[25,4134],{"className":4135},[45],[21,4137,4138],{},"By taking the time to listen and understand the client's perspective, we were able to bridge the gap and find a solution that improved the user experience for everyone. This experience solidified the importance of active listening in the software development process. It allows us to gather valuable user feedback, identify potential issues early on, and ultimately create a product that meets the needs of our users.",[25,4140],{"className":4141},[45],[21,4143,4144],{},"This experience gave me a new perspective, because the struggle wasn't only with being open to get criticism on features that we've been working on for months but also convincing the team that it was important to adjust our workflows. And this was beneficial to the business as it became a portal through which several improvement was done on the feature.",[25,4146],{"className":4147},[36],[38,4149,4151],{"id":4150},"_2-learning-to-be-structured-time-management","2. Learning to be Structured (Time Management)",[21,4153,4154],{},"If you're one to find complete satisfaction from your work alone, you can skip this section to the next... If you're still here I'm guessing you feel like you need some touch of polygamy (not as related to a sexual relation) to keep yourself happy. As an adult, life is definitely not just about work, and it is way too easy to get lost in it.",[25,4156],{"className":4157},[45],[21,4159,4160],{},"This can cause you not to spend enough time with your wife, your friends or do the dumb things you like to do whether it be going to costume parties or playing an instrument. Life is filled with so many dumb things that makes us happy, but we tend not to be able to walk between the lines.",[25,4162],{"className":4163},[45],[21,4165,4166],{},"There are generally three kinds of people in this regard — (1) those who work too much; (2) those who work enough and; (3) those who work too little.",[25,4168],{"className":4169},[45],[21,4171,4172],{},"With the advent of remote working, it is quite easy to jump between these three demographic and it is important to structure your work and other work activities else you might not enjoy life to the fullest. The following are tips to create a structure keep you optimal:",[25,4174],{"className":4175},[45],[4177,4178,4179,4185,4191],"ol",{},[1037,4180,4181,4184],{},[1176,4182,4183],{},"Let work time be work time"," - If you work 9 to 5, work between those hours and drop your computer after then (you have to make rooms for exceptions though)",[1037,4186,4187,4190],{},[1176,4188,4189],{},"Don't take your work to your personal life"," - Go on dates with your girlfriend and spend time with the kids.",[1037,4192,4193],{},[1176,4194,4195],{},"Plan the tasks for the next day the day before",[25,4197],{"className":4198},[45],[4088,4200,4201],{},[21,4202,4203],{},"When you have some sort of structure in your personal life, however minor, that is when you can take this to your professional life and make a difference.",[25,4205],{"className":4206},[36],[38,4208,4210],{"id":4209},"_3-collaboration","3. Collaboration",[21,4212,4213],{},"In as much as there are products one can build alone, large-scale products usually require a team of individuals with their roles clearly stated — even if there would be overlaps. Let me not bore you with long talk, but the simple thing is a larger project/product would need more people and to be relevant, asides from being a good software engineer (skill wise), you cannot run away from the fact that you would need to work with others.",[25,4215],{"className":4216},[45],[4088,4218,4219],{},[21,4220,4221],{},"Alice, a whiz at code, struggled with user interfaces. Ben, a design guru, couldn't write a line of code. Together, they created an app that revolutionized the industry.",[25,4223],{"className":4224},[45],[21,4226,4227],{},"Take this with a grain of salt.",[25,4229],{"className":4230},[36],[38,4232,4234],{"id":4233},"_4-problem-solving","4. Problem Solving",[21,4236,4237],{},"Software engineering is all about problem solving. A good analogy would be your thought and your speech. Your speech is just an audible articulation of your thoughts. This is the same way coding is a syntactic articulation of a solution you have developed for a problem.",[25,4239],{"className":4240},[45],[21,4242,4243],{},"You can develop problem solving skills by:",[25,4245],{"className":4246},[45],[21,4248,4249],{},[1176,4250,4251],{},"a. Practicing with coding challenges",[21,4253,4254,4257],{},[1176,4255,4256],{},"b. Working on open-source projects"," - Contributing to open-source projects exposes you to real-world codebases and challenges also if I'm being honest. The good thing about working on open-source is that you definitely have to think about how others are using your solutions and you would let a great bunch from how others approach problems also.",[21,4259,4260,4263],{},[1176,4261,4262],{},"c. Break down complex problems"," - Usually, a big problem is a combination of smaller ones. Knowing how to efficiently break problem into smaller pieces, solving those and artfully joining them together would be a sharp katana under your belt.",[21,4265,4266,4269],{},[1176,4267,4268],{},"d. Learn from mistakes"," - When we finally stumble on a solution for an unfamiliar problem (eg. a coding problem), it is very common to have gone through several inefficient ones, when you finally get the optimal solution, don't be scared to delete the whole solution and re-write it.",[25,4271],{"className":4272},[36],[38,4274,3971],{"id":3970},[21,4276,4277],{},"In conclusion, while strong coding skills are a valuable foundation, becoming a well-rounded software engineer requires a broader skillset. This includes soft skills like communication, time management, and collaboration to effectively bridge the gap between technical expertise and real-world needs.",[25,4279],{"className":4280},[45],[21,4282,4283],{},"By honing these complementary abilities, software engineers can not only create innovative products but also ensure they are user-friendly, solve genuine problems, and contribute to a successful business model. Remember, software engineering is a team effort, and effective communication and collaboration are essential for turning your problem-solving skills into successful products.",[25,4285],{"className":4286},[36],[932,4288],{},[25,4290],{"className":4291},[36],[21,4293,4294],{},[3992,4295,3994,4296,4300],{},[291,4297,3999],{"href":4298,"rel":4299},"https://medium.com/@dev.davexoyinbo/is-programming-enough-the-tales-of-a-software-engineer-d697057dfd5e",[295]," by David Oyinbo",{"title":347,"searchDepth":403,"depth":403,"links":4302},[4303,4304,4305,4306,4307,4308,4309],{"id":1132,"depth":403,"text":1133},{"id":4079,"depth":403,"text":4080},{"id":4110,"depth":403,"text":4111},{"id":4150,"depth":403,"text":4151},{"id":4209,"depth":403,"text":4210},{"id":4233,"depth":403,"text":4234},{"id":3970,"depth":403,"text":3971},"2024-04-28T00:00:00.000Z","Exploring the essential soft skills beyond programming that software engineers need to succeed in the business world - from communication and time management to collaboration and problem-solving",{},"/engineering-logs/programming-soft-skills","7 min",{"title":4035,"description":4311},"engineering-logs/programming-soft-skills",[1103,4318,4319,4320,4321,4322,4323],"career-development","soft-skills","communication","collaboration","problem-solving","business","AI5cg1IgQNpLnYy7TK27PKTf2Qp-phBLtbR6wlACfko",1781398393233]