2025-07-12 18:00:04
People feel invisible at work when they aren’t recognized and appreciated, passed up for a promotion, or don’t get the opportunity they think they deserve. Irrespective of how hard they work, they keep getting sidelined or ignored.
\ They stay back late in the office, work long hours, take back work home, and give their 100% to anything that’s assigned to them. Despite ticking every item off their to-do list, they constantly face disappointment and dissatisfaction of being overlooked and neglected.
\ Working harder than everyone else will never get them the visibility they want because no one ever gets noticed by simply doing great work. Keeping their head down and continuing to contribute will probably help them hit business targets, but they will miss out on areas where their knowledge and experience could have made a tremendous difference.
\ Making yourself seen at work is important because when your work is visible, not only are you likely to land better opportunities, but you are also more likely to get promoted.
\ But you can’t rely on your manager to do this for you. Your manager has hundreds of things to do, and doing a good job of knowing each team member's strengths and weaknesses may never make it to their priority list. They are flawed and biased in deciding who gets the opportunity, who has knowledge and skills, and who’s ready to succeed at the next level.
\
Basic economics tells us that if you want something rare and valuable, you need to offer something rare and valuable in return—and in the working world, what you have to offer are your skills.
― Jocelyn K. Glei
\ So, how do you get your work noticed, acknowledged, and valued not only by your team members but also those in different teams and functions so that you can put your valuable skills to use?
Employees spend a large part of their time in meetings and discussions, but most attend these meetings without learning anything or saying a word.
\ Not only do they waste time attending these meetings, but they also lose the opportunity to make their knowledge, experience, and skills visible.
\ Participation isn’t the same as attendance. Participation requires active involvement, curiosity, and a desire to contribute. Attendance is passive, where you show up to kill time while staying invisible.
\
When you step into a meeting, you’re entering a shared space for collaboration, decision-making, and exchanging ideas. Treasure this space, and it will turn into a source of joy.
― Marie Kondō
\ Don’t show up in discussions you don’t intend to participate in. Participation does not necessarily require a thoughtful argument, sharing your opinion, or being the person with the best idea in the room. Asking questions that ignite conversations, showing curiosity to understand others, or expressing your desire to help them are great ways to connect with others and share your knowledge and skills.
\ Speak up. Find small ways to contribute to the discussions. Others around you will take notice, which will encourage them to take an interest in you and your work. Visibility isn’t built by showing off or trying hard to prove your worth. Participating in discussions with the right intent can open that door for you.
We think of feedback as a way to highlight expectation mismatch, point out flaws, and tell someone about the gaps in their knowledge and skills. Naturally, it seems counterintuitive to use it as a tool to build visibility around your work.
\ But feedback can significantly enhance the visibility of your work by creating opportunities for engagement, collaboration, and showcasing your commitment to improvement. Asking for feedback invites others to interact with your work. It gives them a reason to pay attention to what you’re doing―they are forced to take a closer look at your thought process, approach, and multiple challenges faced along the way.
\ Building connections this way can amplify the reach and impact of your work because others are more likely to talk about and share work they feel invested in. Regularly seeking and valuing feedback can also foster strong relationships, expand your network, and build trust, making these people become strong advocates for your work, helping to spread the word further than you could ever do alone.
\
Sharing your work and seeking feedback isn’t just about improvement; it’s about letting others see your progress, engage with your ideas, and amplify your voice.
― Dorie Clark
\ Feedback is not only a tool for growth. It’s a great way to invite others into your story, inspiring them to take notice and create a ripple effect that draws more people to your work.
Most of us haven’t been trained to express affection, which can make praising or appreciating others feel awkward and inappropriate. Our own ego may also get in the way of holding others in high regard and recognizing them for their work.
\ But making others feel valued by speaking positively about them, inviting them to share their expertise, or making them feel heard and understood by actively listening to them can increase your visibility at work.
\ When you acknowledge and celebrate others' contributions, they often feel compelled to return the favor. They may be more inclined to mention your contributions during team meetings, highlight your strengths, or invite you to key projects, discussions, and initiatives. We naturally gravitate towards people who uplift us. So, making others feel valued is a strategic way to strengthen relationships, increase your influence, and come across as a supportive colleague.
\ Elevating others by making them feel important will not jeopardize your own position, make your achievements seem less significant, or steal your spotlight. Quite the opposite. The more light you shine on others, the more they are bound to reflect it back to you.
\ But it’s important that your appreciation comes across as genuine, not forced. Others can easily sense when you are complimenting them to earn a favor or trying to manipulate them to see things your way. Fake interactions like these can leave others feeling used, which can make you come across as inauthentic, opportunistic, or dishonest—someone who can’t be trusted or taken seriously.
\
“Next to physical survival, the greatest need of a human being is psychological survival—to be understood, to be affirmed, to be validated, to be appreciated. When you listen with empathy to another person, you give that person psychological air. And after that vital need is met, you can then focus on influencing or problem solving. This need for psychological air impacts communication in every area of life.”
― Stephen R. Covey
\ Demonstrate intellectual curiosity. Show interest in others and their work. People are more likely to reciprocate and show interest in you.
Most people think that facts about their accomplishments and data to back them up will be sufficient to win people over. But data and facts can only get others interested in you and your work.
\ They may temporarily remember the skills, knowledge, and experience you bring to the table. But, all your valuable contributions are soon wiped out as their brain tries to fit other eventful information accumulated during the day.
\ Facts and data may get the attention, but it’s the story that sticks. Stories add emotion and context, which makes your journey more compelling and positions you as someone worth remembering.
\ In trying to make your work more visible, repeating your achievements to others can make you come across as boastful. However, framing your work as a narrative—the challenges you overcame, solutions you implemented, and the results you achieved—can make it more noticeable and appealing, increasing the likelihood for others to remember you long enough.
\ Stories connect with people because they appeal to their emotions. Providing context, stating facts, and sharing data are important. It makes your work credible and is bound to get others' attention. But it isn’t enough to persuade them to advocate for you. Once you have their intellectual attention, you need to tap into their emotions.
\
Emotions drive behavior—Every decision is an emotional decision at some level. Whatever your logical reasons are for taking action, you only feel compelled to act on them because of emotion.
— James Clear
\ Connect, inspire, and make your work unforgettable by turning it into an emotional experience. Good storytelling requires a little bit of creativity to make it memorable, but it’s a skill that can be mastered with practice and experience.
We all seek mentors—people who can guide and coach us—while not paying attention to sponsors—people who can help us get the right opportunities by making our work visible. Sponsors have the real power to shape your career by aligning your aspirations with the opportunities you need and making them possible for you.
\ Even a great product in the market can’t sell by itself. It needs good marketing to get in front of the right customers. This applies to your work too.
\ You need:
Someone to vouch for you.
\ Someone who can help you get the right opportunities by increasing the visibility of your work.
\ Someone who will support and defend you because they believe in you.
\ That someone is a sponsor. Good sponsors can take you to the next level in your career by identifying where your work might be valuable and signing you up for it.
\ Many people mistake sponsors with mentors—they’re not the same. Mentors give you feedback and advice, share their experience, and help you build new skills. Sponsors raise you up by making your experience and skills visible to others and getting you in front of the right opportunities.
\ A mentor can only show you the right door; it’s the sponsor that can open it for you.
\ Sponsorship doesn’t happen by chance. You need to actively put effort into seeking the right sponsor.
Look for people who have a track record of advocating for others and have access to power or leadership circles.
\
Don’t be busy doing work all day long. If you’re running from one task, one project, and one problem to the next, you’ll never have the mental space to notice such people.
\
When you’re part of meetings, discussions, or other gatherings where such people are present, don’t shy away from introducing yourself. Approach them, quickly speak about your work, and immediately shift the focus to them. Showing interest in their life is a great strategy to get their attention.
\
Connect with people from other teams and functions, find ways to help others, and contribute to initiatives outside your direct scope of work. Get sponsored by adding value.
\
Take the time to build authentic relationships. No one will sponsor you unless they also know who you are as a person.
\
“Mentors are valuable for guidance, but sponsors are critical to your career. They put their necks on the line for you, advocate for you in rooms where you aren't present, and ensure you have the opportunities you deserve.”
— Tiffany Dufu
\ Don’t limit yourself to one sponsor. Just like multiple mentors are useful to get guidance and advice, multiple sponsors are necessary to utilize your potential by getting in front of the right opportunities. Each sponsor can open a new door for you. Consciously allocate time to find them—you may never get sponsored unless you actively seek one.
People who are good at producing high-quality work may not be the most sought-after, most valued, or most appreciated. Despite having excellent knowledge and skills, their impact is limited because limited visibility around their work prevents them from getting the right opportunities.
\
Keeping your mouth shut during discussions keeps you invisible. Others can’t appreciate your thought process if you keep it to yourself without saying a word. When you actively participate—by sharing an idea, asking questions, or challenging a decision—others may take notice. Your enthusiasm and curiosity can encourage them to take an interest in you and your work.
\
Seeking feedback may seem counter to your desire to increase visibility at work. But it’s a great tool to give others a peek into everything you have achieved. Feedback invites others to take a closer look at your work—they are forced to pay attention to your knowledge and skills.
\
Appreciating others' contributions not only puts you across as a supportive and caring individual, but it also compels others to reciprocate, too. Kindness attracts kindness. But you have to be authentic. Fake appreciation can make others resent you instead of building trust.
\
Stating your accomplishments as data and facts can’t make it memorable. To stick long enough, it has to appeal to people’s emotions. Creating a story around your work is a great way to increase its appeal, expand its reach, and ensure it leaves a lasting impression.
\
There are people at work who have authority and power to influence key decisions—which projects to take off, who gets the opportunity, and who is ready for the next level. These people can increase your visibility by advocating for you in discussions where you aren’t present. But you have to put in the effort to reach out and showcase your value in a way that turns them into a sponsor.
This story was previously published here. Follow me on LinkedIn or here for more stories.
2025-07-12 14:10:56
How are you, hacker?
🪐Want to know what's trending right now?:
The Techbeat by HackerNoon has got you covered with fresh content from our trending stories of the day! Set email preference here.
## Coinzilla Delivers 75M+ Impressions, Powering Bitget’s 120% Growth in One Month
By @coinzilla [ 3 Min read ]
The results demonstrate how targeted campaigns, effective publisher selection, and real-time optimization can drive scalable growth for crypto brands. Read More.
By @confluent [ 2 Min read ] Learn how PyIceberg simplifies working with Apache Iceberg using Python—no JVM clusters needed. Ideal for small to mid-sized data lakehouses. Read More.
By @oleksiijko [ 2 Min read ] Dive into WebRTC internals: how SDP, ICE/STUN/TURN, and DTLS-SRTP enable secure, real-time media between browsers with no plugins required. Read More.
By @morpheuslord [ 6 Min read ] MCP and ACP protocols are killing entry-level jobs. 94% of IT positions need experience, 90% of tasks automated. Adapt or perish in the AI job apocalypse. Read More.
By @aminbenarieb [ 22 Min read ] Discover how an iPhone was transformed into a powerful laboratory microscope for real-time blood cell analysis using ML, Bluetooth and GRBL controller Read More.
By @brightdata [ 10 Min read ] Let’s uncover what the Playwright MCP server brings to the table, and how to use it with the OpenAI Agents SDK. Read More.
By @Shabhadi [ 9 Min read ] Discover a modern KPI framework for Large Language Model Optimization (LLMO) and how to track SEO visibility across AI tools. Read More.
By @jroseland [ 16 Min read ] Step into the darkly seductive world of Hourglass, a sci-fi novel exploring AI, biohacking, and post-human ethics in a near-future dystopia. Read More.
By @bigmao [ 7 Min read ] Your startup got its first win. Congrats. Now here's 10 things to do so you don't become a parody of your own pitch deck. Read More.
By @wassimchegham [ 4 Min read ] In this post, we’ll demonstrate how to orchestrate Model Context Protocol (MCP) servers in a real-world TypeScript application. Read More.
By @thomascherickal [ 29 Min read ] A 4 trillion USD company is well-established today but that may change as early as next year, thanks to disruptive technology - MLIR and Mojo. Read More.
By @fewshot [ 6 Min read ] A study finds multimodal AI models like CLIP need exponential data for linear gains—raising questions about zero-shot generalization claims. Read More.
By @kishoredasaka [ 4 Min read ] Startups often talk about brand, but very few actually have brand value. This article breaks down what makes a brand financially valuable. Read More.
By @TheMarkup [ 7 Min read ] Here's a guide to turning it off on three of the most popular smart TV software platforms in use last year. Read More.
By @scottdclary [ 3 Min read ] Everything you think is “realistic” about your life is just someone else’s delusion. Read More.
By @jwolinsky [ 9 Min read ] Some language models are learning to recognize the kinds of patterns that usually show up in well-structured, reliable code. Read More.
By @maken8 [ 6 Min read ] Bitcoin Banks will not capture Bitcoin if they're pumping debt into it. They'll orange-pill more decentralized banking. Read More.
By @ozhansisic [ 11 Min read ] Ozhan Sisic explains how to close cybersecurity governance and risk gaps by embedding security into business strategy, not just ticking compliance boxes. Read More.
By @socialdiscoverygroup [ 6 Min read ] Explore how an online dating platform scaled AI moderation with ChatGPT, custom prompt engineering, and in-house data labeling to cut review time 60x. Read More.
By @OurAI [ 7 Min read ]
Read More.
🧑💻 What happened in your world this week? It's been said that writing can help consolidate technical knowledge, establish credibility, and contribute to emerging community standards. Feeling stuck? We got you covered ⬇️⬇️⬇️
ANSWER THESE GREATEST INTERVIEW QUESTIONS OF ALL TIME
We hope you enjoy this worth of free reading material. Feel free to forward this email to a nerdy friend who'll love you for it.
See you on Planet Internet! With love,
The HackerNoon Team ✌️
2025-07-12 09:48:05
Woah, another beta build already? You’re not imagining things, it’s only been a week since our last release. The team is fully in the swing of getting release-blockers merged, so we’re able to expedite output. What’s more, our community has been on the ball with submitting regression reports; thanks to everyone who’s involved themselves!
\ While progress has been at a rate we’re all excited about, it’s not over yet! We’ll likely do one more beta release the following week, but after that we hope to be gearing up for release candidates. If you haven’t already, we encourage users who haven’t engaged with the beta releases to do so and help us catch the last few stragglers.
\ Please, consider supporting the project financially, if you are able. Godot is maintained by the efforts of volunteers and a small team of paid contributors. Your donations go towards sponsoring their work and ensuring they can dedicate their undivided attention to the needs of the project.
\ Jump to the Downloads section, and give it a spin right now, or continue reading to learn more about improvements in this release. You can also try the Web editor or the Android editor for this release. If you are interested in the latter, please request to join our testing group to get access to pre-release builds.
The original cover illustration is from Ballionaire, a roguelike pachinko simulator where the laws of physics bend to your will, developed by newobject and published by Raw Fury! You can buy the game on Steam, and follow the developer on Bluesky and itch.io.
For an overview of what’s new overall in Godot 4.4, have a look at the highlights for 4.4 beta 1, which cover a lot of the changes. This blog post only covers the changes between beta 2 and beta 3. This section covers the most relevant changes made since the beta 2 snapshot, which are largely regression fixes.
The introduction of .uid
files remains one of the biggest changes to the 4.4 release cycle, so much so that we gave it a dedicated article. However, it hasn’t been the most straightforward system, particularly for those that are attempting to upgrade their projects from 4.3. In order to address this, Malcolm Anderson has put together a UID upgrade tool to automate this process (GH-103071).
The Embedded/Floating game window option added in 4.4 is proving to be quite popular, but also exposes all kinds of quirks on various systems with how they deal with windows. Hilderin did impressive work to track and fix these issues, with pull requests such as GH-102104, GH-102238, GH-102251, GH-102311, GH-102312, GH-102470, and more! The experience should be much better already in beta 3.
Clay John changed the logic for baking direct lighting in LightmapGI to spread it over multiple frames, avoiding a spike of computation that can lead the OS to trigger TDR, resulting in a crash of the GPU context (GH-102257). With some further fixes like GH-102424, GH-102497, and GH-102477, lightmap baking got a nice upgrade in this snapshot.
Basis::get_euler
incorrectly simplifying rotations in some cases (GH-102144).is_valid_float
, Variant
parser, Expression
parser, script highlighter, and TextServer
not handing capital E in scientific notation (GH-102396).FlowContainer
for Profiler
and Visual Profiler
bars (GH-102024).ClassDB::bind_method_custom()
fails (GH-102131).Viewport
functions for keeping the mouse over state consistent (GH-99890).FileChooser
and Settings
interface availability instead of assuming it’s always available (GH-101812).get_length()
for pipes (GH-102365).source_color
default value (GH-101642).51 contributors submitted 116 improvements for this release. See our interactive changelog for the complete list of changes since the 4.4-beta2 snapshot. You can also review all changes included in 4.4 compared to the previous 4.3 feature release.
This release is built from commit 06acfccf8
.
\ Standard build includes support for GDScript and GDExtension.
.NET build (marked as mono
) includes support for C#, as well as GDScript and GDExtension.
\ While engine maintainers try their best to ensure that each preview snapshot and release candidate is stable, this is by definition a pre-release piece of software. Be sure to make frequent backups, or use a version control system such as Git, to preserve your projects in case of corruption or data loss.
During the beta stage, we focus on solving both regressions (i.e. something that worked in a previous release is now broken) and significant new bugs introduced by new features. You can have a look at our current list of regressions and significant issues which we aim to address before releasing 4.4. This list is dynamic and will be updated if we discover new showstopping issues after more users start testing the beta snapshots.
\ With every release, we accept that there are going to be various issues which have already been reported but haven’t been fixed yet. See the GitHub issue tracker for a complete list of known bugs.
As a tester, we encourage you to open bug reports if you experience issues with this release. Please check the existing issues on GitHub first, using the search function with relevant keywords, to ensure that the bug you experience is not already known.
\ In particular, any change that would cause a regression in your projects is very important to report (e.g. if something that worked fine in previous 4.x releases, but no longer works in this snapshot).
Godot is a non-profit, open source game engine developed by hundreds of contributors on their free time, as well as a handful of part and full-time developers hired thanks to generous donations from the Godot community. A big thank you to everyone who has contributed their time or their financial support to the project!
\ If you’d like to support the project financially and help us secure our future hires, you can do so using the Godot Development Fund.
Thaddeus Crews
\ Also published here
2025-07-12 09:33:00
The Rust compiler has recently upgraded to using LLVM 19 and this change accompanies some updates to the default set of target features enabled for WebAssembly targets of the Rust compiler. Beta Rust today, which will become Rust 1.82 on 2024-10-17, reflects all of these changes and can be used for testing.
\
WebAssembly is an evolving standard where extensions are being added over time through a proposals process. WebAssembly proposals reach maturity, get merged into the specification itself, get implemented in engines, and remain this way for quite some time before producer toolchains (e.g. LLVM) update to enable these sufficiently-mature proposals by default. In LLVM 19 this has happened with the multi-value and reference-types proposals for the LLVM/Rust target features multivalue
and reference-types
. These are now enabled by default in LLVM and transitively means that it's enabled by default for Rust as well.
\ WebAssembly targets for Rust now have improved documentation about WebAssembly proposals and their corresponding target features. This post is going to review these changes and go into depth about what's changing in LLVM.
WebAssembly proposals are the formal means by which the WebAssembly standard itself is evolved over time. Most proposals need toolchain integration in one form or another, for example new flags in LLVM or the Rust compiler. The -Ctarget-feature=...
mechanism is used to implement this today. This is a signal to LLVM and the Rust compiler which WebAssembly proposals are enabled or disabled.
\
There is a loose coupling between the name of a proposal (often the name of the github repository of the proposal) and the feature name LLVM/Rust use. For example there is the multi-value proposal but a multivalue
feature.
\ The lifecycle of the implementation of a feature in Rust/LLVM typically looks like:
-Ctarget-feature=+foo
-Ctarget-feature=+foo
feature by default but typically retain the ability to disable it as well.\
The reference-types
and multivalue
target features in Rust are at step (4) here now and this post is explaining the consequences of doing so.
The reference-types proposal to WebAssembly introduced a few new concepts to WebAssembly, notably the externref
type which is a host-defined GC resource that WebAssembly cannot access but can pass around. Rust does not have support for the WebAssembly externref
type and LLVM 19 does not change that. WebAssembly modules produced from Rust will continue to not use the externref
type nor have a means of being able to do so.
\
This may be enabled in the future (e.g. a hypothetical core::arch::wasm32::Externref
type or similar), but it will mostly likely only be done on an opt-in basis and will not affect preexisting code by default.
\
Also included in the reference-types proposal, however, was the ability to have multiple WebAssembly tables in a single module. In the original version of the WebAssembly specification only a single table was allowed and this restriction was relaxed with the reference-types proposal. WebAssembly tables are used by LLVM and Rust to implement indirect function calls. For example function pointers in WebAssembly are actually table indices and indirect function calls are a WebAssembly call_indirect
instruction with this table index.
\
With the reference-types proposal the binary encoding of call_indirect
instructions was updated. Prior to the reference-types proposal call_indirect
was encoded with a fixed zero byte in its instruction (required to be exactly 0x00). This fixed zero byte was relaxed to a 32-bit LEB to indicate which table the call_indirect
instruction was using.
\
For those unfamiliar LEB is a way of encoding multi-byte integers in a smaller number of bytes for smaller integers. For example the 32-bit integer 0 can be encoded as 0x00
with a LEB. LEBs are flexible to additionally allow "overlong" encodings so the integer 0 can additionally be encoded as 0x80 0x00
.
\
LLVM's support of separate compilation of source code to a WebAssembly binary means that when an object file is emitted it does not know the final index of the table that is going to be used in the final binary. Before reference-types there was only one option, table 0, so 0x00
was always used when encoding call_indirect
instructions.
\
After reference-types, however, LLVM will emit an over-long LEB of the form 0x80 0x80 0x80 0x80 0x00
which is the maximal length of a 32-bit LEB. This LEB is then filled in by the linker with a relocation to the actual table index that is used by the final module.
\
When putting all of this together, it means that with LLVM 19, which has the reference-types
feature enabled by default, any WebAssembly module with an indirect function call (which is almost always the case for Rust code) will produce a WebAssembly binary that cannot be decoded by engines and tooling that do not support the reference-types proposal.
\ It is expected that this change will have a low impact due to the age of the reference-types proposal and breadth of implementation in engines. Given the multitude of WebAssembly engines, however, it's recommended that any WebAssembly users test out Rust 1.82 beta and see if the produced module still runs on their engine of choice.
One interesting point worth mentioning is that despite the reference-types proposal enabling multiple tables in WebAssembly modules this is not actually taken advantage of at this time by either LLVM or Rust. WebAssembly modules emitted will still have at most one table of functions. This means that the over-long 5-byte encoding of index 0 as 0x80 0x80 0x80 0x80 0x00
is not actually necessary at this time.
\
LLD, LLVM's linker for WebAssembly, wants to process all LEB relocations in a similar manner which currently forces this 5-byte encoding of zero. For example when a function calls another function the call
instruction encodes the target function index as a 5-byte LEB which is filled in by the linker. There is quite often more than one function so the 5-byte encoding enables all possible function indices to be encoded.
\
In the future LLVM might start using multiple tables as well. For example LLVM may have a mode in the future where there's a table-per-function type instead of a single heterogenous table. This can enable engines to implement call_indirect
more efficiently. This is not implemented at this time, however.
\
For users who want a minimally-sized WebAssembly module (e.g. if you're in a web context and sending bytes over the wire) it's recommended to use an optimization tool such as wasm-opt
to shrink the size of the output of LLVM. Even before this change with reference-types it's recommended to do this as wasm-opt
can typically optimize LLVM's default output even further. When optimizing a module through wasm-opt
these 5-byte encodings of index 0 are all shrunk to a single byte.
The second feature enabled by default in LLVM 19 is multivalue
. The multi-value proposal to WebAssembly enables functions to have more than one return value for example. WebAssembly instructions are additionally allowed to have more than one return value as well. This proposal is one of the first to get merged into the WebAssembly specification after the original MVP and has been implemented in many engines for quite some time.
\
The consequences of enabling this feature by default in LLVM are more minor for Rust, however, than enabling the reference-types
feature by default. LLVM's default C ABI for WebAssembly code is not changing even when multivalue
is enabled. Additionally Rust's extern "C"
ABI for WebAssembly is not changing either and continues to match LLVM's (or strives to, differences to LLVM are considered bugs to fix). Despite this though the change has the possibility of still affecting Rust users.
\
Rust for some time has supported an extern "wasm"
ABI on Nightly which was an experimental means of exposing the ability of defining a function in Rust which returned multiple values (e.g. used the multi-value proposal). Due to infrastructural changes and refactorings in LLVM itself this feature of Rust has been removed and is no longer supported on Nightly at all. As a result there is no longer any possible method of writing a function in Rust that returns multiple values at the WebAssembly function type level.
\
In summary this change is expected to not affect any Rust code in the wild unless you were using the Nightly feature of extern "wasm"
in which case you'll be forced to drop support for that and use extern "C"
instead. Supporting WebAssembly multi-return functions in Rust is a broader topic than this post can cover, but at this time it's an area that's ripe for contribution from suitably motivated contributors.
While on the topic of ABIs and the multivalue
feature it's perhaps worth also going over a bit what ABIs mean for WebAssembly. The current definition of the extern "C"
ABI for WebAssembly is documented in the tool-conventions repository and this is what Clang implements for C code as well.
\
LLVM implements enough support for lowering to WebAssembly as well to support all of this. The extern "Rust
ABI is not stable on WebAssembly, as is the case for all Rust targets, and is subject to change over time. There is no reference documentation at this time for what extern "Rust"
is on WebAssembly.
\
The extern "C"
ABI, what C code uses by default as well, is difficult to change because stability is often required across different compiler versions. For example WebAssembly code compiled with LLVM 18 might be expected to work with code compiled by LLVM 20. This means that changing the ABI is a daunting task that requires version fields, explicit markers, etc, to help prevent mismatches.
\
The extern "Rust"
ABI, however, is subject to change over time. A great example of this could be that when the multivalue
feature is enabled the extern "Rust"
ABI could be redefined to use the multiple-return-values that WebAssembly would then support. This would enable much more efficient returns of values larger than 64-bits. Implementing this would require support in LLVM though which is not currently present.
\
This all means that actually using multiple-returns in functions, or the WebAssembly feature that the multivalue
enables, is still out on the horizon and not implemented. First LLVM will need to implement complete lowering support to generate WebAssembly functions with multiple returns, and then extern "Rust"
can be change to use this when fully supported. In the yet-further-still future C code might be able to change, but that will take quite some time due to its cross-version-compatibility story.
This is not the first time that a WebAssembly proposal has gone from off-by-default to on-by-default in LLVM, nor will it be the last. For example LLVM already enables the sign-extension proposal by default which MVP WebAssembly did not have. It's expected that in the not-too-distant future the nontrapping-fp-to-int proposal will likely be enabled by default. These changes are currently not made with strict criteria in mind (e.g. N engines must have this implemented for M years), and there may be breakage that happens.
\ If you're using a WebAssembly engine that does not support the modules emitted by Rust 1.82 beta and LLVM 19 then your options are:
\ The general assumption behind enabling new features by default is that it's a relatively hassle-free operation for end users while bringing performance benefits for everyone (e.g. nontrapping-fp-to-int will make float-to-int conversions more optimal). If updates end up causing hassle it's best to flag that early on so rollout plans can be adjusted if needed.
For a variety of reasons you might be motivated to disable on-by-default WebAssembly features: for example maybe your engine is difficult to update or doesn't support a new feature. Disabling on-by-default features is unfortunately not the easiest task. It is notably not sufficient to use -Ctarget-features=-sign-ext
to disable a feature for just your own project's compilation because the Rust standard library, shipped in precompiled form, is still compiled with the feature enabled.
\
To disable on-by-default WebAssembly proposal it's required that you use Cargo's -Zbuild-std
feature. For example:
$ export RUSTFLAGS=-Ctarget-cpu=mvp
$ cargo +nightly build -Zbuild-std=panic_abort,std --target wasm32-unknown-unknown
This will recompiled the Rust standard library in addition to your own code with the "MVP CPU" which is LLVM's placeholder for all WebAssembly proposals disabled. This will disable sign-ext, reference-types, multi-value, etc.
Alex Crichton on behalf of The Compiler Team
\ Also published here
\ Photo by engin akyurt on Unsplash
2025-07-12 09:07:07
The slices.Clone
function is pretty simple: it makes a copy of a slice of any type.
func Clone[S ~[]E, E any](s S) S {
return append(s[:0:0], s...)
}
\ This works because appending to a slice with zero capacity will allocate a new backing array. The function body winds up being shorter than the function signature, which is in part because the body is short, but also because the signature is long. In this blog post we’ll explain why the signature is written the way that it is.
We’ll start by writing a simple generic Clone
function. This is not the one in the slices
package. We want to take a slice of any element type, and return a new slice.
func Clone1[E any](s []E) []E {
// body omitted
}
\
The generic function Clone1
has a single type parameter E
. It takes a single argument s
which is a slice of type E
, and it returns a slice of the same type. This signature is straightforward for anybody familiar with generics in Go.
\ However, there is a problem. Named slice types are not common in Go, but people do use them.
// MySlice is a slice of strings with a special String method.
type MySlice []string
// String returns the printable version of a MySlice value.
func (s MySlice) String() string {
return strings.Join(s, "+")
}
\
Let’s say that we want to make a copy of a MySlice
and then get the printable version, but with the strings in sorted order.
func PrintSorted(ms MySlice) string {
c := Clone1(ms)
slices.Sort(c)
return c.String() // FAILS TO COMPILE
}
\ Unfortunately, this doesn’t work. The compiler reports an error:
c.String undefined (type []string has no field or method String)
\
We can see the problem if we manually instantiate Clone1
by replacing the type parameter with the type argument.
func InstantiatedClone1(s []string) []string
\
The Go assignment rules allow us to pass a value of type MySlice
to a parameter of type []string
, so calling Clone1
is fine. But Clone1
will return a value of type []string
, not a value of type MySlice
. The type []string
doesn’t have a String
method, so the compiler reports an error.
To fix this problem, we have to write a version of Clone
that returns the same type as its argument. If we can do that, then when we call Clone
with a value of type MySlice
, it will return a result of type MySlice
.
\ We know that it has to look something like this.
func Clone2[S ?](s S) S // INVALID
This Clone2
function returns a value that is the same type as its argument.
\
Here I’ve written the constraint as ?
, but that’s just a placeholder. To make this work we need to write a constraint that will let us write the body of the function. For Clone1
we could just use a constraint of any
for the element type. For Clone2
that won’t work: we want to require that s
be a slice type.
\
Since we know we want a slice, the constraint of S
has to be a slice. We don’t care what the slice element type is, so let’s just call it E
, as we did with Clone1
.
func Clone3[S []E](s S) S // INVALID
\
This is still invalid, because we haven’t declared E
. The type argument for E
can be any type, which means it also has to be a type parameter itself. Since it can be any type, its constraint is any
.
func Clone4[S []E, E any](s S) S
\
This is getting close, and at least it will compile, but we’re not quite there yet. If we compile this version, we get an error when we call Clone4(ms)
.
MySlice does not satisfy []string (possibly missing ~ for []string in []string)
\
The compiler is telling us that we can’t use the type argument MySlice
for the type parameter S
, because MySlice
does not satisfy the constraint []E
. That’s because []E
as a constraint only permits a slice type literal, like []string
. It doesn’t permit a named type like MySlice
.
As the error message hints, the answer is to add a ~
.
func Clone5[S ~[]E, E any](s S) S
\
To repeat, writing type parameters and constraints [S []E, E any]
means that the type argument for S
can be any unnamed slice type, but it can’t be a named type defined as a slice literal. Writing [S ~[]E, E any]
, with a ~
, means that the type argument for S
can be any type whose underlying type is a slice type.
\
For any named type type T1 T2
the underlying type of T1
is the underlying type of T2
. The underlying type of a predeclared type like int
or a type literal like []string
is just the type itself. For the exact details, see the language spec. In our example, the underlying type of MySlice
is []string
.
\
Since the underlying type of MySlice
is a slice, we can pass an argument of type MySlice
to Clone5
. As you may have noticed, the signature of Clone5
is the same as the signature of slices.Clone
. We’ve finally gotten to where we want to be.
\
Before we move on, let’s discuss why the Go syntax requires a ~
. It might seem that we would always want to permit passing MySlice
, so why not make that the default? Or, if we need to support exact matching, why not flip things around, so that a constraint of []E
permits a named type while a constraint of, say, =[]E
, only permits slice type literals?
\
To explain this, let’s first observe that a type parameter list like [T ~MySlice]
doesn’t make sense. That’s because MySlice
is not the underlying type of any other type. For instance, if we have a definition like type MySlice2 MySlice
, the underlying type of MySlice2
is []string
, not MySlice
.
\
So either [T ~MySlice]
would permit no types at all, or it would be the same as [T MySlice]
and only match MySlice
. Either way, [T ~MySlice]
isn’t useful. To avoid this confusion, the language prohibits [T ~MySlice]
, and the compiler produces an error like
invalid use of ~ (underlying type of MySlice is []string)
\
If Go didn’t require the tilde, so that [S []E]
would match any type whose underlying type is []E
, then we would have to define the meaning of [S MySlice]
.
\
We could prohibit [S MySlice]
, or we could say that [S MySlice]
only matches MySlice
, but either approach runs into trouble with predeclared types. A predeclared type, like int
, is its own underlying type. We want to permit people to be able to write constraints that accept any type argument whose underlying type is int
. In the language today, they can do that by writing [T ~int]
. If we don’t require the tilde we would still need a way to say “any type whose underlying type is int
”. The natural way to say that would be [T int]
. That would mean that [T MySlice]
and [T int]
would behave differently, although they look very similar.
\
We could perhaps say that [S MySlice]
matches any type whose underlying type is the underlying type of MySlice
, but that makes [S MySlice]
unnecessary and confusing.
\
We think it’s better to require the ~
and be very clear about when we are matching the underlying type rather than the type itself.
Now that we’ve explained the signature of slices.Clone
, let’s see how actually using slices.Clone
is simplified by type inference. Remember, the signature of Clone
is
func Clone[S ~[]E, E any](s S) S
\
A call of slices.Clone
will pass a slice to the parameter s
. Simple type inference will let the compiler infer that the type argument for the type parameter S
is the type of the slice being passed to Clone
. Type inference is then powerful enough to see that the type argument for E
is the element type of the type argument passed to S
.
\ This means that we can write
c := Clone(ms)
\ without having to write
c := Clone[MySlice, string](ms)
\
If we refer to Clone
without calling it, we do have to specify a type argument for S
, as the compiler has nothing it can use to infer it. Fortunately, in that case, type inference is able to infer the type argument for E
from the argument for S
, and we don’t have to specify it separately.
\ That is, we can write
myClone := Clone[MySlice]
\ without having to write
myClone := Clone[MySlice, string]
The general technique we’ve used here, in which we define one type parameter S
using another type parameter E
, is a way to deconstruct types in generic function signatures. By deconstructing a type, we can name, and constrain, all aspects of the type.
\
For example, here is the signature for maps.Clone
.
func Clone[M ~map[K]V, K comparable, V any](m M) M
\
Just as with slices.Clone
, we use a type parameter for the type of the parameter m
, and then deconstruct the type using two other type parameters K
and V
.
\
In maps.Clone
we constrain K
to be comparable, as is required for a map key type. We can constrain the component types any way we like.
func WithStrings[S ~[]E, E interface { String() string }](s S) (S, []string)
\
This says that the argument of WithStrings
must be a slice type for which the element type has a String
method.
\ Since all Go types can be built up from component types, we can always use type parameters to deconstruct those types and constrain them as we like.
Ian Lance Taylor
\ Photo by Robin Jonathan Deutsch on Unsplash
\ This article is available on The Go Blog under a CC BY 4.0 DEED license.
2025-07-12 09:00:16
You’ve probably used a weather app. Maybe you’ve even built one. But do you actually know what a radar map is really telling you – or hiding from you?
As a developer and founder of Rain Viewer, I’ve spent the last decade parsing radar feeds, filtering out noise, and making chaotic atmospheric data digestible for humans – and APIs. If you’re building anything that touches geolocation, logistics, drones, or weather-dependent automation, understanding radar is more than curiosity – it’s the base.
Here’s your crash course in reading radar like a dev, not a tourist.
First myth to bust: radar doesn’t “see” rain. \n It measures reflectivity (DBZH) – radio waves bouncing off something. That “something” could be:
Most apps simplify this into colored blobs. But that abstraction can hide a lot. Red doesn’t always mean danger, green doesn’t always mean a light shower.
Check RHOHV (correlation coefficient):
Check VRAD (radial velocity):
Check ZDR (differential reflectivity):
Example: if you see a blob with low RHOHV and chaotic VRAD, congratulations – you’ve spotted a swarm of birds.
Radars don’t stream live video – they scan in rotation, upload in batches, then mosaic into frames. Expect 5–10 minutes of latency at best. \n For drones or real-time route optimization, factor this in – or you’re chasing ghosts.
Dev tip:
A single frame is just a snapshot. But storms move fast. \n That cell 20km away, moving at 60 km/h, could be overhead in 20 minutes.
In Rain Viewer, we invested months optimizing storm tracking and arrow overlays – because pattern velocity beats position every time.
Radars don’t just pick up weather. \n Mountains, buildings, planes, wildlife, and temperature inversions all generate false echoes. Here are the common culprits – and how to catch them:
| Artifact | What it looks like | How to detect/filter | |----|----|----| | Ground Clutter | Persistent blob at low elevation | Static masks, Gabella filter | | Death Rings (AP) | Concentric rings expanding outward | Only at low elevation, disappears at higher scans | | Birds/Insects | Smudges that jump in VRAD | Low RHOHV + erratic velocity | | Chaff (military countermeasure) | “Snowflakes” in DBZH, no motion | Very low RHOHV | | Dust/Pollen | Weak streaks moving with wind | Low intensity & high correlation |
Pro tip: The more products you combine, the better your noise filtering.
If you want to experiment yourself, here are reliable open datasets:
Most raw data comes in HDF5, BUFR, or netCDF formats – so be ready to parse.
Whether you’re building a delivery app, an autonomous drone, or just love hacking on weather data, radar literacy is crucial. You’ll stop treating those colorful blobs as gospel – and start seeing the patterns, pitfalls, and possibilities underneath.
Next time you look at a radar map, don’t just check if it’s raining. Read it.
\