Hacktoberfest 2026: los issues que los mantenedores marcaron para octubre, abiertos y aptos para principiantes. Explorar issues de Hacktoberfest

A Changeable Value that can be depend on other adaptive values

Abierto
#114 0 comentarios 0 reacciones 0 asignados Ver en GitHub

Nadie ha tomado este issue todavía.

Evaluación

Dificultad
5/5
Tiempo estimado
Más de una semana
Aptitud para principiantes
25/100
Tipo de issue
Nueva funcionalidad
Claridad
Necesita aclaración
Estado de actividad
Estancado
Stack tecnológico
fsharp
Área
data

Línea de trabajo

Comienza revisando los tipos cval, IAdaptiveValue, AVal.AbstractVal y AdaptiveObject descritos en el issue; después, lee la discusión enlazada sobre AsyncChangeableValue. Se consideraría terminado contar con un diseño definido y documentado para representar valores cambiables dependientes y asíncronos, incluida la decisión sobre si es adecuada una abstracción IChangeableValue o un ChangeableValue extensible.

Escrito por el modelo de indexación a partir del texto del issue.

Descripción

My Team has been using the Fun.Blazor library to do a Blazor UI. In the process we've come across two scenarios in which we'd like a ChangeableValue to depend on another IAdaptiveValue.

  • In the first scenario, We have an incoming ChangeableValue that we want to delay propagating the Mark and Values to until the child has been Committed. We've been calling it DependantChangeableValue<'T> with an implementation like this:
type DependantChangeableValue<'T>(antecedent: cval<'T>) =
    inherit AVal.AbstractVal<'T>()

    // can we avoid double caching (here and in AbstractVal)
    let mutable cache: ValueOption<'T> = ValueNone
        
    override x.Compute(token: AdaptiveToken) =
        match cache with
        | ValueSome v -> v
        | _ ->
            antecedent.GetValue token

    member x.SetValue (v:'T) =
        transact(fun _ ->
            cache <- ValueSome v
            x.MarkOutdated())

    member x.UpdateAntecedent() =
        transact(fun _ ->
            match cache with
            | ValueSome v -> 
                antecedent.Value <- v
            | _ -> ())

    member x.WithSetter() =
        x |> AVal.map(fun v -> v,x.SetValue)
  • In the other case we have a UI component that returns a ChangeableValue which represents the result of the components behavior. It's a Changable value because we want other components or systems to be able to change the UI component by changeing this output (think a selected list where the selected item is 'T option and you can clear the selection by setting to None). But I'd also like to have an input IAdaptiveValue and a setter function able to be optionally passed in that would be able to participate in the Changeable value Mark and SetValue. In this way I might be able to route the SetValue through the returned changeable to the setter function.

In both cases we can definitely implement those capabilities with the current Library but they can be used interchangeably with cval. And it turns out that having the ability to represent changeabilty as type would be sort of nice.

So my question I think it might be useful to to have either an IChangeableValue that derives from IAdaptiveValue and provides the hooks so that code that sees cval can work with any particular implementation or unseal ChangeableValue to allow extension for the same reason. I think the IChangeableValue might be the better route but I wanted some feedback about the suggestion.

Another type we also implemented for representing Async computations that might need to be refreshed after you use them (ex. Database queries with the same arguments):

    type AsyncStatus<'T> =
    | Init
    | Ready of data:'T
    | Loading of msg:string*elapsed:System.TimeSpan
    | Error of msg:string*when':System.DateTimeOffset
    [<StructuredFormatDisplay("{AsString}")>]
    type AsyncChangeableValue<'T>(async':'T Async,?loadingMessage:string,?requireRefresh:bool) as this =
        inherit AdaptiveObject()

        // the initial value is AsyncStatus<'T>.Init
        // thier is also a quiet cache used to attempt refreshing without triggering a change notification until finished

        member x.Value with get                
        member x.GetValue (token: AdaptiveToken) : AsyncStatus<'T>
        /// the async version allows the user to await until the operation is completed to continue with another operation.
        /// if a RefreshQuiet was in progress then it is turned into a normal Refresh operation
        /// if a RefreshAsync in already in flight then this returns an Async<unit> that can be waiting on until the original operation
        /// complete
        /// This cause a Refresh to immediately start and the returned Async<unit> is only used to synchronize with the results. Think Async.StartAsChild(...)
        member x.RefreshAsync() : Async<unit>
        /// this version triggers a refresh and then immediately returns (fire and forget), internally it fires a RefreshAsync and then ignore the resulting Async<unit>
        member x.Refresh() : unit
        /// will cause a refresh of the async computation but will NOT change the state of the cached data
        /// unless it successfully completes. updateOnlyWhenChanged will execute an expensive comparison on
        /// the incoming value to only mark this aval as changed if it is not equal to the current value
        /// ignoreErrors will NOT cause a Change in value if an Error occurs, instead the current value is retained
        /// if a RefreshAsync was in progress then this returns an Async<unit> that can be waited on until the original operation is complete
        /// if a RefreshQuietAsync in already in flight then this returns an Async<unit> that can be waiting on until the original operation
        /// completes
        /// This cause a Refresh to immediately start and the returned Async<unit> is only used to synchronize with the results. Think Async.StartAsChild(...)
        member x.RefreshQuietAsync([<Optional;DefaultParameterValue(false)>]ignoreErrors,[<Optional;DefaultParameterValue(false)>]updateOnlyWhenChanged) : Async<unit>
        /// triggers a RefreshQuietAsync operation and then immediately returns, ignoring the Async<unit> result of RefreshQuiet.
        member x.RefreshQuiet([<Optional;DefaultParameterValue(false)>]ignoreErrors) = x.RefreshQuietAsync(ignoreErrors) |> Async.Start
        member result.MapWithDefault (mapping:'T -> 'U,?defaultValue:'U) : aval<'U>
        member result.IsErrored : aval<bool>
        member result.IsLoading : aval<bool>
        member result.IsReady : aval<bool>
        member result.ReadyValue : aval<'T option>
        member result.LoadingMessage : aval<(string * System.TimeSpan) option>
        member result.ErrorMessage : aval<(string * System.DateTimeOffset) option>


        interface IAdaptiveValue with
            ...

        interface IAdaptiveValue<DataStatus<'T>> with
            ...
        
        member private x.AsString = sprintf "acval(%A)" x.Value
        override x.ToString() = System.String.Format("acval({0})", x.Value)

    and acval<'T> = AsyncChangeableValue<'T>

Thanks in advance for any comments and suggestions.

-Patrick

I just saw this discussion which did discuss something like the AsyncChangeableValue type above: https://github.com/fsprojects/FSharp.Data.Adaptive/discussions/101#discussioncomment-2614410

Lenguaje dominante
F#
Estrellas
255
Forks
25
Métricas de merge de PR
Sin PR fusionados en 30 d

Preparar el entorno

Este proyecto no incluye contenedor de desarrollo, Dockerfile ni guía de contribución, así que la configuración corre por tu cuenta: empieza por su README y consulta nuestra guía para la primera contribución para los pasos generales.

Primeros pasos

  1. Lee el issue completo y luego la guía de contribución del proyecto.
  2. Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
  3. Haz un fork del repositorio y trabaja en una rama.
  4. Abre un pull request que haga referencia al número del issue.

Más de fsprojects/FSharp.Data.Adaptive

Todos los issues de fsprojects/FSharp.Data.Adaptive

Issues similares

Más issues de Data Engineering

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.