Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Do notation #43

Merged
merged 8 commits into from
Jun 22, 2024
Merged

Do notation #43

merged 8 commits into from
Jun 22, 2024

Conversation

taman9333
Copy link
Contributor

@taman9333 taman9333 commented Jun 19, 2024

Description

This PR introduces do-notation to simplify error handling and improve the readability of monadic operations.

Example:

package main

import (
	"errors"
	"fmt"
	"github.com/samber/mo"
)

func validateBooking(params map[string]string) mo.Result[map[string]string] {
	if params["guest"] != "" && params["roomType"] != "" {
		return mo.Ok(params)
	}
	return mo.Err[map[string]string](errors.New("validation failed"))
}

func createBooking(guest string) mo.Result[string] {
	if guest != "" {
		return mo.Ok("Booking Created for: " + guest)
	}
	return mo.Err[string](errors.New("booking creation failed"))
}

func assignRoom(booking string, roomType string) mo.Result[string] {
	if roomType != "" {
		return mo.Ok("Room Assigned: " + roomType + " for " + booking)
	}
	return mo.Err[string](errors.New("room assignment failed"))
}

// This could be a service package that performs the entire process
func bookRoom(params map[string]string) mo.Result[[]string] {
	return mo.Do(func() []string {
		// Validate booking parameters
		values := validateBooking(params).MustGet()

		// Create booking
		booking := createBooking(values["guest"]).MustGet()

		// Assign room
		room := assignRoom(booking, values["roomType"]).MustGet()

		// Return success with booking and room details
		return []string{booking, room}
	})
}

func main() {
	params := map[string]string{
		"guest":   "Foo",
		"roomType": "Suite",
	}

	result := bookRoom(params)
	if result.IsError() {
		fmt.Println("Error:", result.Error())
	} else {
		fmt.Println("Success:", result.MustGet())
	}
}

Benefits:

  • Readability: The code is more concise easier to understand and less verbose.
  • Maintainability: Centralized error handling reduces repetitive boilerplate code.
  • Consistency: Ensures a consistent error handling mechanism throughout the codebase.

Without the do-notation the code becomes much more verbose and less maintainable due to the explicit error handling after each step. By using do-notation, we centralize the error handling logic, resulting in cleaner and more concise code.

Comparison of createService Function:

without do-notation

func bookRoom(params map[string]string) mo.Result[[]string] {
	values, err := validateBooking(params).Get()
	if err != nil {
		return mo.Err[[]string](err)
	}

	booking, err := createBooking(values["guest"]).Get()
	if err != nil {
		return mo.Err[[]string](err)
	}

	room, err := assignRoom(booking, values["roomType"]).Get()
	if err != nil {
		return mo.Err[[]string](err)
	}

	return mo.Ok([]string{booking, room})
}

With do-notation

func bookRoom(params map[string]string) mo.Result[[]string] {
	return Do(func() []string {
		values := validateBooking(params).MustGet()
		booking := createBooking(values["guest"]).MustGet()
		room := assignRoom(booking, values["roomType"]).MustGet()
		return []string{booking, room}
	})
}

@taman9333
Copy link
Contributor Author

@samber

@samber
Copy link
Owner

samber commented Jun 21, 2024

hi @taman9333

I like the idea.

Can you explain why you named it "Do" instead of "Try" or other? Do does not seem meaningful to me. But I might be wrong.

@taman9333
Copy link
Contributor Author

taman9333 commented Jun 21, 2024

@samber I am just following the same naming convention introduced in Haskell Do you prefer a different name?

@taman9333
Copy link
Contributor Author

taman9333 commented Jun 21, 2024

@samber I've fixed those Testable Examples.
Let me know if you have any other comments. You can merge the PR if you don't have any concerns

I have reverted fixing Testable Examples as I have found you fixed that

@samber
Copy link
Owner

samber commented Jun 22, 2024

Yes, I made a fix, while merging another contrib recently.

Thanks for your work

@samber samber merged commit b216a39 into samber:master Jun 22, 2024
0 of 2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants