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

Make the generic type order consistent in the Left, Right, and Either #3650

Open
wants to merge 3 commits into
base: next-major
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions .changeset/eleven-keys-decide.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
---
"effect": major
---

## Major: Swap type parameters for `Left` and `Right` to align with `Either`

**WHAT the breaking change is:**

- The type parameters for `Left<L, R>` and `Right<L, R>` have been swapped to `Left<R, L>` and `Right<R, L>`, respectively. This brings them in line with the parameter ordering of `Either<R, L>`.

**WHY the change was made:**

- This change ensures consistency across the codebase. In `Either<R, L>`, `R` is used for the "right" value and `L` for the "left" value. Aligning `Left` and `Right` with `Either` reduces confusion.

**HOW a consumer should update their code:**

- Any usage of `Left<L, R>` should be replaced with `Left<R, L>`.
- Any usage of `Right<L, R>` should be replaced with `Right<R, L>`.
- For example:
- `Left<string, number>` should now be `Left<number, string>`.
- `Right<string, number>` should now be `Right<number, string>`.
8 changes: 4 additions & 4 deletions packages/effect/src/Effect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -165,13 +165,13 @@ declare module "./Context.js" {
* @category models
*/
declare module "./Either.js" {
interface Left<L, R> extends Effect<R, L> {
interface Left<R, L> extends Effect<R, L> {
readonly _tag: "Left"
[Symbol.iterator](): EffectGenerator<Left<L, R>>
[Symbol.iterator](): EffectGenerator<Left<R, L>>
}
interface Right<L, R> extends Effect<R, L> {
interface Right<R, L> extends Effect<R, L> {
readonly _tag: "Right"
[Symbol.iterator](): EffectGenerator<Right<L, R>>
[Symbol.iterator](): EffectGenerator<Right<R, L>>
}
interface EitherUnifyIgnore {
Effect?: true
Expand Down
10 changes: 5 additions & 5 deletions packages/effect/src/Either.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import * as Gen from "./Utils.js"
* @category models
* @since 2.0.0
*/
export type Either<R, L = never> = Left<L, R> | Right<L, R>
export type Either<R, L = never> = Left<R, L> | Right<R, L>

/**
* @category symbols
Expand All @@ -39,7 +39,7 @@ export type TypeId = typeof TypeId
* @category models
* @since 2.0.0
*/
export interface Left<out L, out R> extends Pipeable, Inspectable {
export interface Left<out R, out L> extends Pipeable, Inspectable {
readonly _tag: "Left"
readonly _op: "Left"
readonly left: L
Expand All @@ -56,7 +56,7 @@ export interface Left<out L, out R> extends Pipeable, Inspectable {
* @category models
* @since 2.0.0
*/
export interface Right<out L, out R> extends Pipeable, Inspectable {
export interface Right<out R, out L> extends Pipeable, Inspectable {
readonly _tag: "Right"
readonly _op: "Right"
readonly right: R
Expand Down Expand Up @@ -233,7 +233,7 @@ export const isEither: (input: unknown) => input is Either<unknown, unknown> = e
* @category guards
* @since 2.0.0
*/
export const isLeft: <R, L>(self: Either<R, L>) => self is Left<L, R> = either.isLeft
export const isLeft: <R, L>(self: Either<R, L>) => self is Left<R, L> = either.isLeft

/**
* Determine if a `Either` is a `Right`.
Expand All @@ -249,7 +249,7 @@ export const isLeft: <R, L>(self: Either<R, L>) => self is Left<L, R> = either.i
* @category guards
* @since 2.0.0
*/
export const isRight: <R, L>(self: Either<R, L>) => self is Right<L, R> = either.isRight
export const isRight: <R, L>(self: Either<R, L>) => self is Right<R, L> = either.isRight

/**
* Converts a `Either` to an `Option` discarding the `Left`.
Expand Down
10 changes: 5 additions & 5 deletions packages/effect/src/Micro.ts
Original file line number Diff line number Diff line change
Expand Up @@ -380,14 +380,14 @@ export declare namespace MicroExit {
* @experimental
* @category MicroExit
*/
export type Success<A, E = never> = Either.Right<MicroCause<E>, A>
export type Success<A, E = never> = Either.Right<A, MicroCause<E>>

/**
* @since 3.4.6
* @experimental
* @category MicroExit
*/
export type Failure<A, E = never> = Either.Left<MicroCause<E>, A>
export type Failure<A, E = never> = Either.Left<A, MicroCause<E>>
}

/**
Expand Down Expand Up @@ -456,23 +456,23 @@ export const exitIsFailure: <A, E>(self: MicroExit<A, E>) => self is MicroExit.F
* @experimental
* @category MicroExit
*/
export const exitIsInterrupt = <A, E>(self: MicroExit<A, E>): self is Either.Left<MicroCause.Interrupt, A> =>
export const exitIsInterrupt = <A, E>(self: MicroExit<A, E>): self is Either.Left<A, MicroCause.Interrupt> =>
exitIsFailure(self) && self.left._tag === "Interrupt"

/**
* @since 3.4.6
* @experimental
* @category MicroExit
*/
export const exitIsFail = <A, E>(self: MicroExit<A, E>): self is Either.Left<MicroCause.Fail<E>, A> =>
export const exitIsFail = <A, E>(self: MicroExit<A, E>): self is Either.Left<A, MicroCause.Fail<E>> =>
exitIsFailure(self) && self.left._tag === "Fail"

/**
* @since 3.4.6
* @experimental
* @category MicroExit
*/
export const exitIsDie = <A, E>(self: MicroExit<A, E>): self is Either.Left<MicroCause.Die, A> =>
export const exitIsDie = <A, E>(self: MicroExit<A, E>): self is Either.Left<A, MicroCause.Die> =>
exitIsFailure(self) && self.left._tag === "Die"

/**
Expand Down
4 changes: 2 additions & 2 deletions packages/effect/src/STM.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,10 +113,10 @@ declare module "./Context.js" {
* @category models
*/
declare module "./Either.js" {
interface Left<L, R> extends STM<R, L> {
interface Left<R, L> extends STM<R, L> {
readonly _tag: "Left"
}
interface Right<L, R> extends STM<R, L> {
interface Right<R, L> extends STM<R, L> {
readonly _tag: "Right"
}
}
Expand Down
20 changes: 10 additions & 10 deletions packages/effect/src/internal/either.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,24 +22,24 @@ const CommonProto = {
[TypeId]: {
_R: (_: never) => _
},
[NodeInspectSymbol]<L, R>(this: Either.Either<R, L>) {
[NodeInspectSymbol]<R, L>(this: Either.Either<R, L>) {
return this.toJSON()
},
toString<L, R>(this: Either.Left<L, R>) {
toString<R, L>(this: Either.Left<R, L>) {
return format(this.toJSON())
}
}

const RightProto = Object.assign(Object.create(CommonProto), {
_tag: "Right",
_op: "Right",
[Equal.symbol]<L, R>(this: Either.Right<L, R>, that: unknown): boolean {
[Equal.symbol]<R, L>(this: Either.Right<R, L>, that: unknown): boolean {
return isEither(that) && isRight(that) && Equal.equals(this.right, that.right)
},
[Hash.symbol]<L, R>(this: Either.Right<L, R>) {
[Hash.symbol]<R, L>(this: Either.Right<R, L>) {
return Hash.combine(Hash.hash(this._tag))(Hash.hash(this.right))
},
toJSON<L, R>(this: Either.Right<L, R>) {
toJSON<R, L>(this: Either.Right<R, L>) {
return {
_id: "Either",
_tag: this._tag,
Expand All @@ -51,13 +51,13 @@ const RightProto = Object.assign(Object.create(CommonProto), {
const LeftProto = Object.assign(Object.create(CommonProto), {
_tag: "Left",
_op: "Left",
[Equal.symbol]<L, R>(this: Either.Left<L, R>, that: unknown): boolean {
[Equal.symbol]<R, L>(this: Either.Left<R, L>, that: unknown): boolean {
return isEither(that) && isLeft(that) && Equal.equals(this.left, that.left)
},
[Hash.symbol]<L, R>(this: Either.Left<L, R>) {
[Hash.symbol]<R, L>(this: Either.Left<R, L>) {
return Hash.combine(Hash.hash(this._tag))(Hash.hash(this.left))
},
toJSON<E, A>(this: Either.Left<E, A>) {
toJSON<A, E>(this: Either.Left<A, E>) {
return {
_id: "Either",
_tag: this._tag,
Expand All @@ -70,10 +70,10 @@ const LeftProto = Object.assign(Object.create(CommonProto), {
export const isEither = (input: unknown): input is Either.Either<unknown, unknown> => hasProperty(input, TypeId)

/** @internal */
export const isLeft = <R, L>(ma: Either.Either<R, L>): ma is Either.Left<L, R> => ma._tag === "Left"
export const isLeft = <R, L>(ma: Either.Either<R, L>): ma is Either.Left<R, L> => ma._tag === "Left"

/** @internal */
export const isRight = <R, L>(ma: Either.Either<R, L>): ma is Either.Right<L, R> => ma._tag === "Right"
export const isRight = <R, L>(ma: Either.Either<R, L>): ma is Either.Right<R, L> => ma._tag === "Right"

/** @internal */
export const left = <L>(left: L): Either.Either<never, L> => {
Expand Down
2 changes: 1 addition & 1 deletion packages/platform/src/Cookies.ts
Original file line number Diff line number Diff line change
Expand Up @@ -552,7 +552,7 @@ export const setAll: {
for (const [name, value, options] of cookies) {
const either = makeCookie(name, value, options)
if (Either.isLeft(either)) {
return either as Either.Left<CookiesError, never>
return either as Either.Left<never, CookiesError>
}
record[name] = either.right
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ const schema = S.Struct({
const decodeUnknownEither = S.decodeUnknownEither(schema)
const input = { a: { b: { c: "" } } }
const result = decodeUnknownEither(input)
const issue = (result as any as Either.Left<ParseResult.ParseError, unknown>).left.issue
const issue = (result as any as Either.Left<unknown, ParseResult.ParseError>).left.issue

// console.log(issue)

Expand Down