phone

    • chevron_right

      The XMPP Standards Foundation: The XMPP Newsletter February 2023

      news.movim.eu / PlanetJabber • 5 March, 2023 • 5 minutes

    Welcome to the XMPP Newsletter, great to have you here again! This issue covers the month of February 2023. Many thanks to all our readers and all contributors!

    Like this newsletter, many projects and their efforts in the XMPP community are a result of people’s voluntary work. If you are happy with the services and software you may be using, please consider saying thanks or help these projects! Interested in supporting the Newsletter team? Read more at the bottom .

    XSF Announcements

    xmpp.org got a new software section! Looking for XMPP software, i.e. clients, servers, libraries, components, and tools? Check out xmpp.org ’s new software section , which lets you filter software by your own criteria. Looking for a client which works on Android and supports audio/video calls? Looking for a library that supports XEP-0461: Message Replies ? Just apply the filter and see what you get!

    xmpp.org’s new software section

    xmpp.org’s new software section

    XMPP and Google Summer of Code 2023

    The XSF has been accepted again as hosting organisation at the GSoC 2023 !

    XSF and Google Summer of Code 2023

    XSF and Google Summer of Code 2023

    XSF fiscal hosting projects

    The XSF offers fiscal hosting for XMPP projects. Please apply via Open Collective . For more information, see the announcement blog post . Current projects:

    XMPP Events

    XMPP Videos

    Articles

    Software news

    Clients and applications

    • Converse 10.1.1 and 10.1.2 have been released, which both fix some bugs. Converse is a web based XMPP/Jabber chat client.
    • Dino 0.4.0 ‘Ilulissat’ and 0.4.1 have been released. The 0.4 release adds support for message reactions and replies. Dino also switched from GTK3 to GTK4 and makes use of libadwaita now.
    Dino 0.4 now supports Message Replies and Message Reactions

    Dino 0.4 now supports Message Replies and Message Reactions

    • Gajim 1.7.0 and 1.7.1 have been released. These releases bring improved KeepassXC integration, better defaults for group chats created with ejabberd, and some important bug fixes.
    • Psi+ 1.5.1645 and 1.5.1646 have been released.

    Servers

    Libraries & Tools

    Extensions and specifications

    The XMPP Standards Foundation develops extensions to XMPP in its XEP series in addition to XMPP RFCs .

    Developers and other standards experts from around the world collaborate on these extensions, developing new specifications for emerging practices, and refining existing ways of doing things. Proposed by anybody, the particularly successful ones end up as Final or Active - depending on their type - while others are carefully archived as Deferred. This life cycle is described in XEP-0001 , which contains the formal and canonical definitions for the types, states, and processes. Read more about the standards process . Communication around Standards and Extensions happens in the Standards Mailing List ( online archive ).

    Proposed

    The XEP development process starts by writing up an idea and submitting it to the XMPP Editor. Within two weeks, the Council decides whether to accept this proposal as an Experimental XEP.

    • No XEPs proposed this month.

    New

    • No new XEPs this month.

    Deferred

    If an experimental XEP is not updated for more than twelve months, it will be moved off Experimental to Deferred. If there is another update, it will put the XEP back onto Experimental.

    • No XEPs deferred this month.

    Updated

    • No XEPs updated this month.

    Last Call

    Last calls are issued once everyone seems satisfied with the current XEP status. After the Council decides whether the XEP seems ready, the XMPP Editor issues a Last Call for comments. The feedback gathered during the Last Call help improving the XEP before returning it to the Council for advancement to Stable.

    • No Last Call this month.

    Stable

    • No XEP moved to stable this month.

    Deprecated

    • No XEP deprecated this month.

    Call for Experience

    A Call For Experience - like a Last Call, is an explicit call for comments, but in this case it’s mostly directed at people who’ve implemented, and ideally deployed, the specification. The Council then votes to move it to Final.

    • No Call for Experience this month.

    Spread the news!

    Please share the news on other networks:

    Subscribe to the monthly XMPP newsletter
    Subscribe

    Also check out our RSS Feed !

    Looking for job offers or want to hire a professional consultant for your XMPP project? Visit our XMPP job board .

    Newsletter Contributors & Translations

    This is a community effort, and we would like to thank translators for their contributions. Volunteers are welcome! Translations of the XMPP Newsletter will be released here (with some delay):

    • English (original): xmpp.org
      • General contributors: Adrien Bourmault (neox), Alexander “PapaTutuWawa”, emus, Licaon_Kter, Ludovic Bocquet, MattJ, MSavoritias (fae,ve), wurstsalat, Zash
    • French: jabberfr.org and linuxfr.org
      • Translators: Adrien Bourmault (neox), alkino, anubis, Benoît Sibaud, Pierre Jarillon, Ppjet6, Ysabeau
    • German: xmpp.org and anoxinon.de
      • Translators: Jeybe, wh0nix
    • Italian: notes.nicfab.eu
      • Translators: nicfab
    • Spanish: xmpp.org
      • Translators: daimonduff, TheCoffeMaker

    Help us to build the newsletter

    This XMPP Newsletter is produced collaboratively by the XMPP community. Each month’s newsletter issue is drafted in this simple pad . At the end of each month, the pad’s content is merged into the XSF Github repository . We are always happy to welcome contributors. Do not hesitate to join the discussion in our Comm-Team group chat (MUC) and thereby help us sustain this as a community effort. You have a project and want to spread the news? Please consider sharing your news or events here, and promote it to a large audience.

    Tasks we do on a regular basis:

    • gathering news in the XMPP universe
    • short summaries of news and events
    • summary of the monthly communication on extensions (XEPs)
    • review of the newsletter draft
    • preparation of media images
    • translations
    • communication via media accounts

    License

    This newsletter is published under CC BY-SA license .

    • wifi_tethering open_in_new

      This post is public

      xmpp.org /2023/03/the-xmpp-newsletter-february-2023/

    • chevron_right

      Ignite Realtime Blog: Translations everywhere!

      news.movim.eu / PlanetJabber • 2 March, 2023

    Two months ago, we started using Transifex as a platform that can be easily used by anyone to provide projects for our projects, like Openfire and Spark.

    It is great to see that new translations are pouring in! In the last few months, more than 20,000 translated words have been provided by our community!

    We’ve enabled the Transifex platform for most of the Openfire plugins (that require translations) today. If you are proficient in a non-English language, please join the translation effort !

    1 post - 1 participant

    Read full topic

    • chevron_right

      Erlang Solutions: Getting started with RabbitMQ: A beginner’s guide for your business

      news.movim.eu / PlanetJabber • 2 March, 2023 • 4 minutes

    RabbitMQ is one of the world’s most popular open-source message brokers. With its tens of thousands of users (and growing), its lightweight and easy-to-deploy nature makes it a worldwide success across small startups and large enterprises across the globe.

    But how do you know if it’s best for your business?

    Read on and get the rundown on the reliable messaging software that delivers every time.

    So, what exactly is RabbitMQ?

    RabbitMQ is an open-source message broker software that implements the Advanced Message Queuing Protocol (AMQP). It is used to facilitate communication between applications or microservices, by allowing them to send and receive messages in a reliable and scalable way.

    Simply put, RabbitMQ acts as a mediator between applications that need to exchange messages. It acts as a message queue, where producers can send messages, and then consumers can receive and process them. It ensures that messages are delivered in order, without loss, and provides features such as routing, failover, and message persistence.

    RabbitMQ is a highly powerful tool for building complex, scalable, and reliable communication systems between applications.

    What is a Message Broker?

    A message broker is an intermediary component that sits between applications and helps them communicate with each other.

    Basic set-up of a message queue: CloudAMP

    In short, applications send messages to the broker. The broker then sends the message to the intended receiver. This separates sending and receiving applications, allowing them to scale independently.

    The message broker also acts as a buffer between sending and receiving applications. It ensures that messages are delivered in the most timely and efficient manner possible.

    In RabbitMQ, messages that are stored in queues and applications can also post and consume messages from them, too. It supports multiple messaging models including point-to-point, publish/subscribe, and request/reply, making it a flexible solution for many use cases.

    By using RabbitMQ as a message broker, developers can decouple the components of their system, allowing them to build more resilient, scalable, and resilient applications.

    So why should I choose RabbitMQ?

    We’ve already touched on this slightly but, there are several reasons why RabbitMQ is a popular choice for implementing message-based systems for your business:

    It’s scalable: RabbitMQ can handle large amounts of messages and can be easily scaled up.

    It’s flexible: RabbitMQ supports multiple messaging models, including point-to-point, publish/subscribe and request/reply.

    It’s reliable: RabbitMQ provides many features to ensure reliable message delivery, including message confirmation, message persistence, and auto-recovery.

    Its Interoperability: RabbitMQ implements the AMQP standard, making it interoperable with multiple platforms and languages.

    To learn more about RabbitMQ’s impressive problem-solving capabilities, you can delve into our technical deep dive detailing its delivery.

    What are the benefits of using RabbitMQ for my business?

    RabbitMQ’s popularity because of its range of benefits, including:

    Decoupled architecture: RabbitMQ allows applications to communicate with each other through a centralised message queue, decoupling- sending and receiving applications. This allows for a flexible and extensible architecture, in which components can scale independently.

    Performance improvement: RabbitMQ can handle large volumes of messages. It also has low latency, which improves overall system performance.

    Reliable messaging: RabbitMQ provides many features to ensure reliable messaging, including message confirmation, message retention, and auto-recovery.

    Flexible Messaging Model: RabbitMQ supports a variety of messaging models, including point-to-point, publish/subscribe, and request/reply, enabling a flexible and adaptable messaging system response.

    Interoperability: RabbitMQ implements the AMQP standard, making it interoperable with multiple platforms and languages.

    But don’t just take our word for it.

    Erlang’s world- leading RabbitMQ experts have been trusted with implementing RabbitMQ for some of the world’s biggest brands.

    You can read more about their experience and the success of RabbitMQ in their business.

    When should I start to consider using RabbitMQ?

    Wondering when the right time is to start implementing RabbitMQ as your messaging system? If you’re ready for reliable, scalable, and flexible communication between your applications, it might be time to consider.

    Here are some common use cases for RabbitMQ:

    Decoupled Architecture: RabbitMQ allows you to build a decoupled architecture, in which different components of your system can communicate together- without the need for a tight coupling. This makes your system more flexible, extensible and resilient.

    Asynchronous communication: When you need to implement asynchronous communication between applications, RabbitMQ can help. For example, do you have a system that needs to process large amounts of data? RabbitMQ can be used to offload that processing to a separate component, allowing the parent component to continue processing requests, meanwhile, the data is processed in the background.

    Microservices: RabbitMQ is well-suited to a microservices architecture, where different components of your system are implemented as separate services. It provides a communication infrastructure, allowing these services to communicate with each other.

    Integrating with legacy systems: Do you have legacy systems that need to communicate with each other? RabbitMQ can provide a common messaging infrastructure that allows those systems to exchange messages.

    High Availability and Reliability: RabbitMQ provides features such as message persistence, automatic failover, and replication, making it a reliable solution for mission-critical applications.

    Multi-Protocol Support: RabbitMQ supports multiple messaging protocols, including AMQP, MQTT, and STOMP, making it a flexible solution for different types of applications.

    Ultimately, the choice is yours to use RabbitMQ or any other messaging system, as it all comes down to your specific business needs.

    I would like to get started with RabbitMQ!

    Whether you are building a small application or a large-scale system, RabbitMQ is a great solution to enable inter-component communication.

    We appreciate that you might have further questions, and our team of expert consultants are on hand and ready to talk you through the process. Just head to our contact page .

    The post Getting started with RabbitMQ: A beginner’s guide for your business appeared first on Erlang Solutions .

    • wifi_tethering open_in_new

      This post is public

      www.erlang-solutions.com /blog/getting-started-with-rabbitmq-a-beginners-guide-for-your-business/

    • chevron_right

      JMP: Cheogram Android: Stickers

      news.movim.eu / PlanetJabber • 1 March, 2023 • 3 minutes

    One feature people ask about from time to time is stickers.  Now, “stickers” isn’t really a feature, nor is it even universally agreed what it means, but we’ve been working on some improvements to Cheogram Android (and the Cheogram service) to make some sticker workflows better, released today in 2.12.1-3 .  This post will mostly talk about those changes and the technical implications; if you just want to see a demo of some UI you may want to skip to the video demo .

    Many Android users already have pretty good support for inserting stickers (or GIFs) into Cheogram Android via their keyboard.  However, as the app existed at the time, this would result in the sender re-uploading and the recipient re-downloading the sticker image every time, and fill up the sending server and receiving device with many copies of the same image.  The first step to mitigating this was to switch local media storage in the app to content-addressed, which in this case means that the file is named after the hash of its contents .  This prevents filling up the device when receiving the same image many times.

    Now that we know the hashes of our stored media, we can use SIMS to transmit this hash when sending.  If the app sees an image that it already has, it can display it without downloading at all, saving not only space but bandwidth and time as well.  The Cheogram service also uses SIMS to transmit hashes of incoming MMS images for this purpose as well.

    An existing Jabber client which uses the word “stickers” is Movim .  It wouldn’t make sense to add the word to our UI without supporting what they already have.  So we added support for XHTML-IM including Bits of Binary images.  This also relies on hash-based storage or caching, which by now we had.  This tech will also be useful in the future to extend beyond stickers into custom emoji.

    Some stickers are animated, and users want to be able to send GIFs as well, so the app was updated to support inline playback of animated images (both GIF and WebP format).

    Some users don’t have any sticker support in their keyboard or OS, so we want to provide some tools for these users as well.  We have added the option to download some default sticker packs (mostly curated from the default set from Movim for now) so that users start with some options.  We also built a small proxy to allow easily importing stickers intended for signal by clicking the regular “add to signal” links on eg signalstickers.com .  Any sticker selected from these will get sent without even uploading, saving time and space on the server, and then will be received by any user of the app who has the default packs installed with no need for downloading, with fallbacks for other clients and situations of course.

    If a user receives a sticker that they’d like to save for easily sending out again later, they can long-press any image they receive and choose “Save as sticker” which will prompt them to choose or create a sticker pack to keep it in, then save it there.  Pointing a sticker sheet app or keyboard at this directory also allows re-using other sticker selection UIs with custom stickers saved in this way.

    Taken together we hope these features produce real benefits for users of stickers, both with and without existing keyboard support, and also provide foundational work that we can build upon to provide custom emoji, thumbnails before downloading, URL previews, and other rich media features in the future.  If you’d like to see some of these features in action, check out this short video .

    • wifi_tethering open_in_new

      This post is public

      blog.jmp.chat /b/cheogram-android-stickers-2023

    • chevron_right

      Debian XMPP Team: XMPP What's new in Debian 12 bookworm

      news.movim.eu / PlanetJabber • 1 March, 2023 • 3 minutes

    On Tue 13 July 2021 there was a blog post of new XMPP related software releases which have been uploaded to Debian 11 (bullseye). Today, we will inform you about updates for the upcoming Debian release bookworm.

    A lot of new releases have been provided by the upstream projects. There were lot of changes to the XMPP clients like Dino, Gajim, Profanity, Poezio and others. Also the XMPP servers have been enhanced.

    Unfortunately, we can not provide a list of all the changes which have been done, but will try to highlight some of the changes and new features.

    BTW, feel free to join the Debian User Support on Jabber at xmpp:debian@conference.debian.org?join .

    You can find a list of 58 packages of the Debian XMPP team on the XMPP QA Page .

    • Dino , modern XMPP client has been upgraded from 0.2.0 to 0.4.0. The new version supports encrypted calls and group calls and reactions give you a way to respond to a message with an emoji. You can find more information about Dino 0.3.0 and Dino 0.4.0 in the release notes of the upstream project. Dino is using GTK4 / libadwaita which provides widgets for mobile-friendly UIs. Changes has been done on the main view of Dino.
    • Gajim , a GTK+-based Jabber client has been upgraded from 1.3.1 to 1.7.1. Since 1.4 Gajim has got a new UI, which supports spaces. 1.5.2 supports a content viewer for PEP nodes. 1.6.0 is using libsoup3 and python 3.10. Audio preview looks a lot nicer with a wave graph visualization and profile images (avatar) are not limited to only JPG anymore. The plugins gajim-appindicatorintegration, gajim-plugininstaller, gajim-syntaxhighlight und gajim-urlimagepreview are obsolete, these features has been moved to gajim. There were a lot of releases in Gajim. You can find the full story at https://gajim.org/post/
    • Profanity , the console based XMPP client has been upgraded from 0.10.0 to 0.13.1. Profanity supports XEP-0377 Spam Reporting, and XEP-0157 server contact information discovery. It now marks a window with an attention flag, updated HTTP Upload XEP-0363, and messages can be composed with an external editor. It also features easy quoting, in-band account registration (XEP-0077), Print OMEMO verification QR code, and many more.
    • Kaidan , a simple and user-friendly Jabber/XMPP client based on Qt has been updated from 0.7.0 to 0.8.0. The new release supports XEP-0085: Chat State Notifications and XEP-0313: Message Archive Management.
    • Poezio , a console-based XMPP client as been updated from 0.13.1 to 0.14. Poezio is now under GPLv3+. The new release supports request for voice and the /join command support using an XMPP URI. More information at https://lab.louiz.org/poezio/poezio/-/raw/v0.14/CHANGELOG.
    • [Swift][swift-im], back in Debian is the Swift XMPP client - a cross-platform Client written in C++. In 2015 the client was removed from testing and is back with version 5.0.

    Server

    • prosody the lightweight extensible XMPP server has been upgraded from 0.11.9 to 0.12.2. Mobile and connectivity optimizations, a new module for HTTP file sharing, audio/video calling support. See the release announcement for more info. You will also find a lot of new modules which have been added to 0.12.0 . The version 0.12.3 is waiting migration from unstable to testing.
    • ejabberd , extensible realtime platform (XMPP server + MQTT broker + SIP service) has been updated from Version 21.01 to 23.01. The new version supports the latest version of MIX (XEP-0369). There were also changes for SQL and MUC. See the release information for 22.10 and 23.01 for more details.

    Libs

    • libstrophe , xmpp C lib has been upgraded from 0.10.1 to 0.12.2. The lib has SASL EXTERNAL support (XEP-0178), support for manual certificate verification and Stream Management support (XEP-0198).
    • python-nbxmpp 2.0.2 to 4.2.0 - used by gajim
    • qxmpp 1.3.2 to 1.4.0
    • slixmpp 1.7.0 to 1.8.3 (see https://lab.louiz.org/poezio/slixmpp/-/tags/slix-1.8.0)
    • loudmouth 1.5.3 to 1.5.4
    • libomemo-c , new in Debian with version 0.5.0 - a fork of libsignal-protocol-c

    Others

    • There were some changes of the Libervia, formerly known as Salut à Toi (SaT) packages in Debian. The most visible change is, that Salut à Toi has been renamed to libervia:
    • salutatoi is now libervia-backend (0.9.0)
    • sat-xmpp-primitivus is now libervia-tui
    • sat-xmpp-core is now libervia-backend
    • sat-xmpp-jp is now libervia-cli
    • sat-pubsub is now libervia-pubsub (0.4.0)
    • gsasl has been updated from 1.10.0 to 2.2.0
    • libxeddsa 2.0.0 is new in Debian - toolkit around Curve25519 and Ed25519 key pairs

    Happy chatting - keep in touch with your family and friends via Jabber / XMPP - XMPP is an open standard of the Internet Engineering Task Force (IETF) for instant messaging.

    • chevron_right

      The XMPP Standards Foundation: XMPP at Google Summer of Code 2023

      news.movim.eu / PlanetJabber • 27 February, 2023

    XSF and Google Summer of Code 2023

    XSF and Google Summer of Code 2023

    The XSF has been accepted again as hosting organisation at the Google Summer of Code 2023 !

    Now both students and open-source newcomers are invited to consider and review a participation and prepare for the application phase. We would like to invite you to review XMPP projects that signed up with their ideas for this year.

    XMPP Projects at Google Summer of Code 2023

    Projects which signed up are:

    Designated Web Page

    We have further details and advertisement material on our designated web page presented in various languages.

    Checkout our media channels!

    Looking forward

    –The XSF Organisation Admin

    • wifi_tethering open_in_new

      This post is public

      xmpp.org /2023/02/xmpp-at-google-summer-of-code-2023/

    • chevron_right

      Ignite Realtime Blog: inVerse Openfire plugin 10.1.2-1 released!

      news.movim.eu / PlanetJabber • 24 February, 2023

    Earlier today, version 10.1.2 release 1 of the Openfire inVerse plugin was released. This plugin allows you to easily deploy the third-party Converse client in Openfire. In this release, the version of the client that is bundled in the plugin is updated to 10.1.2!

    The updated plugin should become available for download in your Openfire admin console in the course of the next few hours. Alternatively, you can download the plugin directly, from the plugin’s archive page .

    For other release announcements and news follow us on Twitter

    1 post - 1 participant

    Read full topic

    • chevron_right

      Ignite Realtime Blog: New: Openfire MUC Real-Time Block List plugin!

      news.movim.eu / PlanetJabber • 23 February, 2023 • 1 minute

    A new plugin has been made available for Openfire, our cross-platform real-time collaboration server based on the XMPP protocol. We have named this new plugin the MUC Real-Time Block List plugin.

    This plugin can help you moderate your chat rooms, especially when your service is part of a larger network of federated XMPP domains. From experience, the XMPP community has learned that bad actors tend to spam a wide range of public chat rooms on an equally wide range of different domains. Prior to the functionality provided by this plugin, the administrator of each MUC service had to manually adjust permissions, to keep unwanted entities out. With this new plugin, that process is automated.

    This plugin can be used to subscribe to a Publish/Subscribe node (as defined in XEP-0060 ), that can live on a remote XMPP domain, but curated by a trusted (group of) administrators). It is expected that this node contains a list of banned entities. When Openfire, through the plugin, is notified that the list has received a new banned entity, it will prevent that entity from joining a chat room in Openfire (if they’re already in, they will be kicked out automatically). Using this mechanism, moderation efforts centralized in one federated Pub/Sub service can be used by any server that uses this plugin.

    This plugin is heavily inspired, and aspires to be compatible with, Prosody’s mod_muc_rtbl and the pub/sub services that it uses.

    The first version of this plugin is now available on our website and should become available in the list of installable plugins in your instance of Openfire in the next few hours. Please give it a test! We are interested in hearing back from you!

    For other release announcements and news follow us on Twitter

    1 post - 1 participant

    Read full topic

    • chevron_right

      Erlang Solutions: Can’t Live `with` It, Can’t Live `with`out It

      news.movim.eu / PlanetJabber • 23 February, 2023 • 8 minutes

    I’d like to share some thoughts about Elixir’s with keyword. with is a wonderful tool, but in my experience it is a bit overused.  To use it best, we must understand how it behaves in all cases.  So, let’s briefly cover the basics, starting with pipes in Elixir.

    Pipes are a wonderful abstraction

    But like all tools, you should think about when it is best used…

    Pipes are at their best when you expect your functions to accept and return basic values. But often we don’t have only simple values because we need to deal with error cases . For example:

    region 
    
    |> Module.fetch_companies() 
    
    |> Module.fetch_departments() 
    
    |> Enum.map(& &1.employee_count) 
    
    |> calculate_average()

    If our fetch_* methods return list values there isn’t a problem. But often we fetch data from an external source, which means we introduce the possibility of an error . Generally in Elixir this means {:ok, _} tuples for success and {:error, _} tuples for failure. Using pipes that might become:

    region
    
    |> Module.fetch_companies()
    
    |> case do
    
      {:ok, companies} -> Module.fetch_departments(companies)
    
      {:error, _} = error -> error
    
    end
    
    |> case do
    
      {:ok, departments} ->
    
        departments
    
        |> Enum.map(& &1.employee_count)
    
        |> calculate_average()
    
      {:error, _} = error -> error
    
    end

    Not horrible, but certainly not beautiful. Fortunately, Elixir has with !

    `with` is a wonderful abstraction

    But like all tools, you should think about when it’s best used…

    with is at it’s best when dealing with the happy paths of a set of calls which all return similar things . What do I mean by that? Let’s look at what this code might look like using with ?

    with {:ok, companies} <- Module.fetch_companies(region),
    
         {:ok, departments} <- Module.fetch_departments(companies) do
    
      departments
    
      |> Enum.map(& &1.employee_count)
    
      |> calculate_average()
    
    end

    That’s definitely better!

    • We separated out the parts of our code which might fail (remember that failure is a sign of a side-effect and in functional programming we want to isolate side-effects).
    • The body is only the things that we don’t expect to fail.
    • We don’t need to explicitly deal with the {:error, _} cases (in this case with will return any clause values which don’t match the pattern before <-) .

    But this is a great example of a happy path where the set of calls all return similar things . But where are some examples of where we might go wrong with with ?

    Non-standard failure

    What if Module.fetch_companies returns {:error, _} but `Module.fetch_departments` returns just :error ? That means your with is going to return two different error results. If your with is the end of your function call then that complexity is now the caller’s responsibility. You might not think that’s a big deal because we can do this:

    else
    
      :error -> {:error, "Error fetching departments"}

    But this breaks to more-or-less important degrees because:

    • … once you add an else clause, you need to take care of every non-happy path case (e.g. above we should match the {:error, _} returned by Module.fetch_companies which we didn’t need to explicitly match before) 😤
    • … if either function is later refactored to return another pattern (e.g. {:error, _, _} ) – there will be a WithClauseError exception (again, because once you add an else the fallback behavior of non-matching <- patterns doesn’t work) 🤷‍♂️
    • … if Module.fetch_departments is later refactored to return {:error, _} – we’ll then have an unused handler 🤷‍♂️
    • … if another clause is added which also returns :error the message Error fetching departments probably won’t be the right error 🙈
    • … if you want to refactor this code later, you need to understand *everything* that the called functions might potentially return, leading to code which is hard to refactor.  If there are just two clauses and we’re just calling simple functions, that’s not as big of a deal.  But with many with clauses which call complex functions, it can become a nightmare 🙀

    So the first major thing to know when using with is what happens when a clause doesn’t match it’s pattern :

    • If else is not specified then the non-matching clause is returned.
    • If else is specified then the code for the first matching else pattern is evaluated. If no else pattern matches , a WithClauseError is raised.

    As Stratus3D excellently put it: “ with blocks are the only Elixir construct that implicitly uses the same else clauses to handle return values from different expressions. The lack of a one-to-one correspondence between an expression in the head of the with block and the clauses that handle its return values makes it impossible to know when each else clause will be used”. There are a couple of well known solutions to address this.  One is using “tagged tuples”:

    with {:fetch_companies, {:ok, companies} <- {:fetch_companies, Module.fetch_companies(region)},
    
         {:fetch_departments, {:ok, departments} <- {:fetch_departments, Module.fetch_departments(companies)},
    
      departments
    
      |> Enum.map(& &1.employee_count)
    
      |> calculate_average()
    
    else
    
      {:fetch_companies, {:error, reason}} -> ...
    
      {:fetch_departments, :error} -> ...
    
    end

    Though tagged tuples should be avoided for various reasons:

    • They make the code a lot more verbose
    • else is now being used, so we need to match all patterns that might occur
    • We need to keep the clauses and else in sync when adding/removing/modifying clauses, leaving room for bugs.
    • Most importantly: the value in an abstraction like {:ok, _} / {:error, _} tuples is that you can handle things generically without needing to worry about the source

    A generally better solution is to create functions which normalize the values matched in the patterns.  This is covered well in a note in the docs for with and I recommend checking it out.  One addition I would make: in the above case you could leave the Module.fetch_companies alone and just surround the Module.fetch_departments with a local fetch_departments to turn the :error into an {:error, reason} .

    Non-standard success

    We can even get unexpected results when with succeeds! To start let’s look at the parse/1 function from the excellent decimal library. It’s typespec tells us that it can return {Decimal.t(), binary()} or :error . If we want to match a decimal value without extra characters, we could have a with clause like this:

    with {:ok, value} <- fetch_value(),
    
         {decimal, ""} <- Decimal.parse(value) do
    
      {:ok, decimal}

    But if value is given as "1.23 " (with a space at the end), then Decimal.parse/1 will return {#Decimal<1.23>, " "} . Since that doesn’t match our pattern (string with a space vs. an empty string), the body of the with will be skipped. If we don’t have an else then instead of returning a {:ok, _} value, we return {#Decimal<1.23>, " "} .

    The solution may seem simple: match on {decimal, _} ! But then we match strings like “1.23a” which is what we were trying to avoid. Again, we’re likely better off defining a local parse_decimal function which returns {:ok, _} or {:error, _} .

    There are other, similar, situations:

    • {:ok, %{"key" => value}} <- fetch_data(...) – the value inside of the {:ok, _} tuple may not have a "key" key.
    • [%{id: value}] <- fetch_data(...) – the list returned may have more or less than one item, or if it does only have one item it may not have the :id key
    • value when length(value) > 2 <- fetch_data(...) – the when might not match. There are two cases where this might surprise you:
      • If value is a list, the length of the list being 2 or below will return the list.
      • If value is a string, length isn’t a valid function (you’d probably want byte_size ). Instead of an exception, the guard simply fails and the pattern doesn’t match.

    The problem in all of these cases is that the intermediate value from fetch_data will be returned, not what the body of the with would return. This means that our with returns “uneven” results. We can handle these cases in the else , but again, once we introduce else we need to take care of all potential cases.

    I might even go to the extent of recommending that you don’t define with clause patterns which are at all deep in their pattern matching unless you are very sure the success case will be able to match the whole pattern .  One example where you might take a risk is when matching %MyStruct{key: value} <- … where you know that a MyStruct value is going to be returned and you know that key is one of the keys defined for the struct. No matter the case, dialyzer is one tool to gain confidence that you will be able to match on the pattern (at least for your own code or libraries which also use dialyzer).

    One of the simplest and most standard ways to avoid these issues is to make sure the functions that you are calling return {:ok, variable} or {:error, reason} tuples. Then with can fall through cleanly ( definitely check out Chris Keathley’s discussion of “Avoid else in with blocks” in his post “Good and Bad Elixir” ).

    With all that said, I recommend using with statements whenever you can! Just make sure that you think about fallback cases that might happen. Even better: write tests to cover all of your potential cases! If you can strike a balance and use with carefully, your code can be both cleaner and more reliable.

    Need help with Elixir?

    We’ve helped 100’s of the world’s biggest companies achieve success with Elixir. From digital transformation, developing fit-for-purposes software for your business logic, to proof-of-concepts, right through to staff augmentation development and support. We’re here to make sure your system makes the most of Elixir to be scalable, reliable and easy to maintain. Talk to us to learn more.

    Training

    Want to improve your Elixir skills? Our world-leading experts are here to help. Learn from the same team who architect, manage and develop some of the biggest in-production systems available. Head to our training page to learn more about our courses and tutorials.

    The post Can’t Live `with` It, Can’t Live `with`out It appeared first on Erlang Solutions .