Git Product home page Git Product logo

Comments (3)

mikeshardmind avatar mikeshardmind commented on September 27, 2024 1

Is there a way to remove behaviour from a type with OrderedIntersection and a Protocol, while having the resulting type still compatible with a type that supports that behaviour?

It depends on what you mean by being compatible. You can specify such an intersection, and then in the scope where that intersection is what is known, limit the behavior of things done to a value consistent with it, but it's still a requirement that the actual type is consistent with all operands, so this is really only something that helps detect issues statically. I suppose that's actually okay for things like replicating ReadOnly but it wasn't a goal to create that capability, just a side effect of using consistent, easy to implement rules that interact well with all of the goals we had and helped resolve an issue of ambiguity with gradual types.

class PreventsListMutationViaMethods(Protocol):
    def append(x: typing.Never, /) -> Never: ...
    # etc

def example(x: OrderedIntersection[PreventsListMutationViaMethods, list[int]]):
    x.append(1)  # This would be a type error, 1 isn't consistent with Never (from PreventsListMutationViaMethods.append) in this context

x: OrderedIntersection[PreventsListMutationViaMethods, list[int]] = [1, 2, 3]  # this is fine
example(x)  # this is fine
example([1,2,3])  # this is fine too

# however

def why_not_actually_read_only(x: list[int]):
    x.append(1)

why_not_actually_read_only(x)  # this is also fine
y: list[int] = x  # This is also fine

you somewhat got to that being the case with:

def as_first_type(x: OrderedIntersection[A, B]) -> A:
  return x

def as_second_type(x: OrderedIntersection[A, B]) -> B:
  return x

So it's not as strict as ReadOnly, not a full replacement for it, and such a protocol hiding the mutable capabilities only applies to the specific scope where that is what you are treating it as the intersection. Overall consistency and subtyping rules still require you being able to treat it as either operand individually if you want to.

If you just want to know if it's possible, and not the why, you can skip the below, but I've included it based on the rest of the post

This particular comment and the two after it may help clarify a bit: #41 (comment)

Importantly, OrderedIntersection in an annotation context does not ever directly equate to a runtime type, but to a specification of specific qualities of one or more runtime types that values need to conform to, this distinction prevents a few issues with the interaction with gradual types, but that's a very long discussion that was had over the course of months, and it would take a while to rehash it. A summary of why this was necessary will be included in the PEP draft.

(Without rehashing all of it, you can explore the difference between what you are allowed to do with class MyList(Any, list[int]): pass and class MyList(list[int], Any): pass to get a sense for why an order wasn't just expedient but necessary to differing desired behavior)

Additional definitions will be proposed as part of this to help discuss this and other cases where the distinction between typing special forms in an annotation context and concrete types in an annotation context carry additional meaning due to them only being "type-like" at runtime due to implementation, while being intended to describe things at a level of description above types in the type system.

It wasn't strictly a goal of adding ordering to create the possibility to place a more restrictive bound on usage, but the possibility was observed to follow from the rules, and seeing as it was easy to find real use cases which could benefit from leaving this capability in place, I cannot see myself attempting to find yet another construction that fits all of our needs, but removes this capability, nor one that makes the capability more powerful and a true replacement for something like ReadOnly

If you have any other questions on this, I'd love to hear them as anything unclear about this will absolutely need to be clearer by the time of proposal.

from intersection_examples.

alicederyn avatar alicederyn commented on September 27, 2024

Interesting. So you end up with a type that superficially seems like it has removed some operations, but does not prevent you accidentally "reenabling" them by calling a function that uses the unrestricted parent type.

I'm curious what use cases were found for this.

from intersection_examples.

mikeshardmind avatar mikeshardmind commented on September 27, 2024

I'm curious what use cases were found for this.

copied from the other thread:

__all__ = ["X",]

class _X:
    def foo(self, _private_cache: dict[str, int] = {}) -> int:
        """
        The private cache being implemented this way prevents the issues of lru_cache on methods...
        """
        ...

class ProtoFoo:
    def foo(self) -> int:
        ...

X: type[OrderedIntersection[ProtoFoo, _X]] = _X

This is better than a library lying about the interface in a typestub instead, as subclassing of the provided type will be detected at an issue if it can no longer be used as _X, but the public type exports the supported interface by users. This one won't have a situation where you accidentally go to having _X, as _X wasn't exported to users, they have to intentionally use something private, and it should be meaningfully obvious to them that this isn't supported by the library.

It's not the most useful extra behavior, but it's a neat side effect of what we otherwise need.

from intersection_examples.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.